diff --git a/backend/src/baserow/core/formula/parser/generated/BaserowFormula.interp b/backend/src/baserow/core/formula/parser/generated/BaserowFormula.interp index 2867b10bf2..e863cab988 100644 --- a/backend/src/baserow/core/formula/parser/generated/BaserowFormula.interp +++ b/backend/src/baserow/core/formula/parser/generated/BaserowFormula.interp @@ -180,4 +180,4 @@ identifier atn: -[3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 3, 85, 96, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 3, 2, 3, 2, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 3, 45, 10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 7, 3, 55, 10, 3, 12, 3, 14, 3, 58, 11, 3, 5, 3, 60, 10, 3, 3, 3, 3, 3, 5, 3, 64, 10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 7, 3, 83, 10, 3, 12, 3, 14, 3, 86, 11, 3, 3, 4, 3, 4, 3, 5, 3, 5, 3, 6, 3, 6, 3, 7, 3, 7, 3, 7, 2, 3, 4, 8, 2, 4, 6, 8, 10, 12, 2, 11, 3, 2, 6, 7, 4, 2, 16, 16, 75, 75, 4, 2, 63, 63, 69, 69, 4, 2, 32, 32, 66, 66, 4, 2, 43, 44, 54, 55, 4, 2, 39, 39, 41, 41, 3, 2, 3, 5, 3, 2, 27, 28, 3, 2, 29, 30, 2, 108, 2, 14, 3, 2, 2, 2, 4, 63, 3, 2, 2, 2, 6, 87, 3, 2, 2, 2, 8, 89, 3, 2, 2, 2, 10, 91, 3, 2, 2, 2, 12, 93, 3, 2, 2, 2, 14, 15, 5, 4, 3, 2, 15, 16, 7, 2, 2, 3, 16, 3, 3, 2, 2, 2, 17, 18, 8, 3, 1, 2, 18, 64, 7, 27, 2, 2, 19, 64, 7, 28, 2, 2, 20, 64, 7, 24, 2, 2, 21, 64, 7, 23, 2, 2, 22, 64, 9, 2, 2, 2, 23, 24, 5, 6, 4, 2, 24, 25, 5, 4, 3, 14, 25, 64, 3, 2, 2, 2, 26, 27, 7, 17, 2, 2, 27, 28, 5, 4, 3, 2, 28, 29, 7, 18, 2, 2, 29, 64, 3, 2, 2, 2, 30, 31, 7, 8, 2, 2, 31, 32, 7, 17, 2, 2, 32, 33, 5, 10, 6, 2, 33, 34, 7, 18, 2, 2, 34, 64, 3, 2, 2, 2, 35, 36, 7, 9, 2, 2, 36, 37, 7, 17, 2, 2, 37, 38, 7, 24, 2, 2, 38, 64, 7, 18, 2, 2, 39, 40, 7, 10, 2, 2, 40, 41, 7, 17, 2, 2, 41, 42, 5, 10, 6, 2, 42, 44, 7, 11, 2, 2, 43, 45, 7, 5, 2, 2, 44, 43, 3, 2, 2, 2, 44, 45, 3, 2, 2, 2, 45, 46, 3, 2, 2, 2, 46, 47, 5, 10, 6, 2, 47, 48, 7, 18, 2, 2, 48, 64, 3, 2, 2, 2, 49, 50, 5, 8, 5, 2, 50, 59, 7, 17, 2, 2, 51, 56, 5, 4, 3, 2, 52, 53, 7, 11, 2, 2, 53, 55, 5, 4, 3, 2, 54, 52, 3, 2, 2, 2, 55, 58, 3, 2, 2, 2, 56, 54, 3, 2, 2, 2, 56, 57, 3, 2, 2, 2, 57, 60, 3, 2, 2, 2, 58, 56, 3, 2, 2, 2, 59, 51, 3, 2, 2, 2, 59, 60, 3, 2, 2, 2, 60, 61, 3, 2, 2, 2, 61, 62, 7, 18, 2, 2, 62, 64, 3, 2, 2, 2, 63, 17, 3, 2, 2, 2, 63, 19, 3, 2, 2, 2, 63, 20, 3, 2, 2, 2, 63, 21, 3, 2, 2, 2, 63, 22, 3, 2, 2, 2, 63, 23, 3, 2, 2, 2, 63, 26, 3, 2, 2, 2, 63, 30, 3, 2, 2, 2, 63, 35, 3, 2, 2, 2, 63, 39, 3, 2, 2, 2, 63, 49, 3, 2, 2, 2, 64, 84, 3, 2, 2, 2, 65, 66, 12, 11, 2, 2, 66, 67, 9, 3, 2, 2, 67, 83, 5, 4, 3, 12, 68, 69, 12, 10, 2, 2, 69, 70, 9, 4, 2, 2, 70, 83, 5, 4, 3, 11, 71, 72, 12, 9, 2, 2, 72, 73, 9, 5, 2, 2, 73, 83, 5, 4, 3, 10, 74, 75, 12, 8, 2, 2, 75, 76, 9, 6, 2, 2, 76, 83, 5, 4, 3, 9, 77, 78, 12, 7, 2, 2, 78, 79, 9, 7, 2, 2, 79, 83, 5, 4, 3, 8, 80, 81, 12, 13, 2, 2, 81, 83, 5, 6, 4, 2, 82, 65, 3, 2, 2, 2, 82, 68, 3, 2, 2, 2, 82, 71, 3, 2, 2, 2, 82, 74, 3, 2, 2, 2, 82, 77, 3, 2, 2, 2, 82, 80, 3, 2, 2, 2, 83, 86, 3, 2, 2, 2, 84, 82, 3, 2, 2, 2, 84, 85, 3, 2, 2, 2, 85, 5, 3, 2, 2, 2, 86, 84, 3, 2, 2, 2, 87, 88, 9, 8, 2, 2, 88, 7, 3, 2, 2, 2, 89, 90, 5, 12, 7, 2, 90, 9, 3, 2, 2, 2, 91, 92, 9, 9, 2, 2, 92, 11, 3, 2, 2, 2, 93, 94, 9, 10, 2, 2, 94, 13, 3, 2, 2, 2, 8, 44, 56, 59, 63, 82, 84] \ No newline at end of file +[3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 3, 85, 99, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 3, 2, 3, 2, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 3, 45, 10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 7, 3, 55, 10, 3, 12, 3, 14, 3, 58, 11, 3, 5, 3, 60, 10, 3, 3, 3, 3, 3, 5, 3, 64, 10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 7, 3, 86, 10, 3, 12, 3, 14, 3, 89, 11, 3, 3, 4, 3, 4, 3, 5, 3, 5, 3, 6, 3, 6, 3, 7, 3, 7, 3, 7, 2, 3, 4, 8, 2, 4, 6, 8, 10, 12, 2, 10, 3, 2, 6, 7, 4, 2, 16, 16, 75, 75, 4, 2, 63, 63, 69, 69, 4, 2, 43, 44, 54, 55, 4, 2, 39, 39, 41, 41, 3, 2, 3, 5, 3, 2, 27, 28, 3, 2, 29, 30, 2, 112, 2, 14, 3, 2, 2, 2, 4, 63, 3, 2, 2, 2, 6, 90, 3, 2, 2, 2, 8, 92, 3, 2, 2, 2, 10, 94, 3, 2, 2, 2, 12, 96, 3, 2, 2, 2, 14, 15, 5, 4, 3, 2, 15, 16, 7, 2, 2, 3, 16, 3, 3, 2, 2, 2, 17, 18, 8, 3, 1, 2, 18, 64, 7, 27, 2, 2, 19, 64, 7, 28, 2, 2, 20, 64, 7, 24, 2, 2, 21, 64, 7, 23, 2, 2, 22, 64, 9, 2, 2, 2, 23, 24, 5, 6, 4, 2, 24, 25, 5, 4, 3, 15, 25, 64, 3, 2, 2, 2, 26, 27, 7, 17, 2, 2, 27, 28, 5, 4, 3, 2, 28, 29, 7, 18, 2, 2, 29, 64, 3, 2, 2, 2, 30, 31, 7, 8, 2, 2, 31, 32, 7, 17, 2, 2, 32, 33, 5, 10, 6, 2, 33, 34, 7, 18, 2, 2, 34, 64, 3, 2, 2, 2, 35, 36, 7, 9, 2, 2, 36, 37, 7, 17, 2, 2, 37, 38, 7, 24, 2, 2, 38, 64, 7, 18, 2, 2, 39, 40, 7, 10, 2, 2, 40, 41, 7, 17, 2, 2, 41, 42, 5, 10, 6, 2, 42, 44, 7, 11, 2, 2, 43, 45, 7, 5, 2, 2, 44, 43, 3, 2, 2, 2, 44, 45, 3, 2, 2, 2, 45, 46, 3, 2, 2, 2, 46, 47, 5, 10, 6, 2, 47, 48, 7, 18, 2, 2, 48, 64, 3, 2, 2, 2, 49, 50, 5, 8, 5, 2, 50, 59, 7, 17, 2, 2, 51, 56, 5, 4, 3, 2, 52, 53, 7, 11, 2, 2, 53, 55, 5, 4, 3, 2, 54, 52, 3, 2, 2, 2, 55, 58, 3, 2, 2, 2, 56, 54, 3, 2, 2, 2, 56, 57, 3, 2, 2, 2, 57, 60, 3, 2, 2, 2, 58, 56, 3, 2, 2, 2, 59, 51, 3, 2, 2, 2, 59, 60, 3, 2, 2, 2, 60, 61, 3, 2, 2, 2, 61, 62, 7, 18, 2, 2, 62, 64, 3, 2, 2, 2, 63, 17, 3, 2, 2, 2, 63, 19, 3, 2, 2, 2, 63, 20, 3, 2, 2, 2, 63, 21, 3, 2, 2, 2, 63, 22, 3, 2, 2, 2, 63, 23, 3, 2, 2, 2, 63, 26, 3, 2, 2, 2, 63, 30, 3, 2, 2, 2, 63, 35, 3, 2, 2, 2, 63, 39, 3, 2, 2, 2, 63, 49, 3, 2, 2, 2, 64, 87, 3, 2, 2, 2, 65, 66, 12, 12, 2, 2, 66, 67, 9, 3, 2, 2, 67, 86, 5, 4, 3, 13, 68, 69, 12, 11, 2, 2, 69, 70, 9, 4, 2, 2, 70, 86, 5, 4, 3, 12, 71, 72, 12, 10, 2, 2, 72, 73, 9, 5, 2, 2, 73, 86, 5, 4, 3, 11, 74, 75, 12, 9, 2, 2, 75, 76, 9, 6, 2, 2, 76, 86, 5, 4, 3, 10, 77, 78, 12, 8, 2, 2, 78, 79, 7, 32, 2, 2, 79, 86, 5, 4, 3, 9, 80, 81, 12, 7, 2, 2, 81, 82, 7, 66, 2, 2, 82, 86, 5, 4, 3, 8, 83, 84, 12, 14, 2, 2, 84, 86, 5, 6, 4, 2, 85, 65, 3, 2, 2, 2, 85, 68, 3, 2, 2, 2, 85, 71, 3, 2, 2, 2, 85, 74, 3, 2, 2, 2, 85, 77, 3, 2, 2, 2, 85, 80, 3, 2, 2, 2, 85, 83, 3, 2, 2, 2, 86, 89, 3, 2, 2, 2, 87, 85, 3, 2, 2, 2, 87, 88, 3, 2, 2, 2, 88, 5, 3, 2, 2, 2, 89, 87, 3, 2, 2, 2, 90, 91, 9, 7, 2, 2, 91, 7, 3, 2, 2, 2, 92, 93, 5, 12, 7, 2, 93, 9, 3, 2, 2, 2, 94, 95, 9, 8, 2, 2, 95, 11, 3, 2, 2, 2, 96, 97, 9, 9, 2, 2, 97, 13, 3, 2, 2, 2, 8, 44, 56, 59, 63, 85, 87] \ No newline at end of file diff --git a/backend/src/baserow/core/formula/parser/generated/BaserowFormula.py b/backend/src/baserow/core/formula/parser/generated/BaserowFormula.py index 18ed44f363..bccc961123 100644 --- a/backend/src/baserow/core/formula/parser/generated/BaserowFormula.py +++ b/backend/src/baserow/core/formula/parser/generated/BaserowFormula.py @@ -12,39 +12,39 @@ def serializedATN(): with StringIO() as buf: buf.write("\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\3U") - buf.write("`\4\2\t\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7\t\7\3\2") + buf.write("c\4\2\t\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7\t\7\3\2") buf.write("\3\2\3\2\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3") buf.write("\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3") buf.write("\3\3\3\3\5\3-\n\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\7\3") buf.write("\67\n\3\f\3\16\3:\13\3\5\3<\n\3\3\3\3\3\5\3@\n\3\3\3\3") buf.write("\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3") - buf.write("\3\3\3\3\7\3S\n\3\f\3\16\3V\13\3\3\4\3\4\3\5\3\5\3\6\3") - buf.write("\6\3\7\3\7\3\7\2\3\4\b\2\4\6\b\n\f\2\13\3\2\6\7\4\2\20") - buf.write("\20KK\4\2??EE\4\2 BB\4\2+,\66\67\4\2\'\'))\3\2\3\5\3") - buf.write("\2\33\34\3\2\35\36\2l\2\16\3\2\2\2\4?\3\2\2\2\6W\3\2\2") - buf.write("\2\bY\3\2\2\2\n[\3\2\2\2\f]\3\2\2\2\16\17\5\4\3\2\17\20") - buf.write("\7\2\2\3\20\3\3\2\2\2\21\22\b\3\1\2\22@\7\33\2\2\23@\7") - buf.write("\34\2\2\24@\7\30\2\2\25@\7\27\2\2\26@\t\2\2\2\27\30\5") - buf.write("\6\4\2\30\31\5\4\3\16\31@\3\2\2\2\32\33\7\21\2\2\33\34") - buf.write("\5\4\3\2\34\35\7\22\2\2\35@\3\2\2\2\36\37\7\b\2\2\37 ") - buf.write("\7\21\2\2 !\5\n\6\2!\"\7\22\2\2\"@\3\2\2\2#$\7\t\2\2$") - buf.write("%\7\21\2\2%&\7\30\2\2&@\7\22\2\2\'(\7\n\2\2()\7\21\2\2") - buf.write(")*\5\n\6\2*,\7\13\2\2+-\7\5\2\2,+\3\2\2\2,-\3\2\2\2-.") - buf.write("\3\2\2\2./\5\n\6\2/\60\7\22\2\2\60@\3\2\2\2\61\62\5\b") - buf.write("\5\2\62;\7\21\2\2\638\5\4\3\2\64\65\7\13\2\2\65\67\5\4") - buf.write("\3\2\66\64\3\2\2\2\67:\3\2\2\28\66\3\2\2\289\3\2\2\29") - buf.write("<\3\2\2\2:8\3\2\2\2;\63\3\2\2\2;<\3\2\2\2<=\3\2\2\2=>") - buf.write("\7\22\2\2>@\3\2\2\2?\21\3\2\2\2?\23\3\2\2\2?\24\3\2\2") + buf.write("\3\3\3\3\3\3\3\3\3\3\7\3V\n\3\f\3\16\3Y\13\3\3\4\3\4\3") + buf.write("\5\3\5\3\6\3\6\3\7\3\7\3\7\2\3\4\b\2\4\6\b\n\f\2\n\3\2") + buf.write("\6\7\4\2\20\20KK\4\2??EE\4\2+,\66\67\4\2\'\'))\3\2\3\5") + buf.write("\3\2\33\34\3\2\35\36\2p\2\16\3\2\2\2\4?\3\2\2\2\6Z\3\2") + buf.write("\2\2\b\\\3\2\2\2\n^\3\2\2\2\f`\3\2\2\2\16\17\5\4\3\2\17") + buf.write("\20\7\2\2\3\20\3\3\2\2\2\21\22\b\3\1\2\22@\7\33\2\2\23") + buf.write("@\7\34\2\2\24@\7\30\2\2\25@\7\27\2\2\26@\t\2\2\2\27\30") + buf.write("\5\6\4\2\30\31\5\4\3\17\31@\3\2\2\2\32\33\7\21\2\2\33") + buf.write("\34\5\4\3\2\34\35\7\22\2\2\35@\3\2\2\2\36\37\7\b\2\2\37") + buf.write(" \7\21\2\2 !\5\n\6\2!\"\7\22\2\2\"@\3\2\2\2#$\7\t\2\2") + buf.write("$%\7\21\2\2%&\7\30\2\2&@\7\22\2\2\'(\7\n\2\2()\7\21\2") + buf.write("\2)*\5\n\6\2*,\7\13\2\2+-\7\5\2\2,+\3\2\2\2,-\3\2\2\2") + buf.write("-.\3\2\2\2./\5\n\6\2/\60\7\22\2\2\60@\3\2\2\2\61\62\5") + buf.write("\b\5\2\62;\7\21\2\2\638\5\4\3\2\64\65\7\13\2\2\65\67\5") + buf.write("\4\3\2\66\64\3\2\2\2\67:\3\2\2\28\66\3\2\2\289\3\2\2\2") + buf.write("9<\3\2\2\2:8\3\2\2\2;\63\3\2\2\2;<\3\2\2\2<=\3\2\2\2=") + buf.write(">\7\22\2\2>@\3\2\2\2?\21\3\2\2\2?\23\3\2\2\2?\24\3\2\2") buf.write("\2?\25\3\2\2\2?\26\3\2\2\2?\27\3\2\2\2?\32\3\2\2\2?\36") - buf.write("\3\2\2\2?#\3\2\2\2?\'\3\2\2\2?\61\3\2\2\2@T\3\2\2\2AB") - buf.write("\f\13\2\2BC\t\3\2\2CS\5\4\3\fDE\f\n\2\2EF\t\4\2\2FS\5") - buf.write("\4\3\13GH\f\t\2\2HI\t\5\2\2IS\5\4\3\nJK\f\b\2\2KL\t\6") - buf.write("\2\2LS\5\4\3\tMN\f\7\2\2NO\t\7\2\2OS\5\4\3\bPQ\f\r\2\2") - buf.write("QS\5\6\4\2RA\3\2\2\2RD\3\2\2\2RG\3\2\2\2RJ\3\2\2\2RM\3") - buf.write("\2\2\2RP\3\2\2\2SV\3\2\2\2TR\3\2\2\2TU\3\2\2\2U\5\3\2") - buf.write("\2\2VT\3\2\2\2WX\t\b\2\2X\7\3\2\2\2YZ\5\f\7\2Z\t\3\2\2") - buf.write("\2[\\\t\t\2\2\\\13\3\2\2\2]^\t\n\2\2^\r\3\2\2\2\b,8;?") - buf.write("RT") + buf.write("\3\2\2\2?#\3\2\2\2?\'\3\2\2\2?\61\3\2\2\2@W\3\2\2\2AB") + buf.write("\f\f\2\2BC\t\3\2\2CV\5\4\3\rDE\f\13\2\2EF\t\4\2\2FV\5") + buf.write("\4\3\fGH\f\n\2\2HI\t\5\2\2IV\5\4\3\13JK\f\t\2\2KL\t\6") + buf.write("\2\2LV\5\4\3\nMN\f\b\2\2NO\7 \2\2OV\5\4\3\tPQ\f\7\2\2") + buf.write("QR\7B\2\2RV\5\4\3\bST\f\16\2\2TV\5\6\4\2UA\3\2\2\2UD\3") + buf.write("\2\2\2UG\3\2\2\2UJ\3\2\2\2UM\3\2\2\2UP\3\2\2\2US\3\2\2") + buf.write("\2VY\3\2\2\2WU\3\2\2\2WX\3\2\2\2X\5\3\2\2\2YW\3\2\2\2") + buf.write("Z[\t\7\2\2[\7\3\2\2\2\\]\5\f\7\2]\t\3\2\2\2^_\t\b\2\2") + buf.write("_\13\3\2\2\2`a\t\t\2\2a\r\3\2\2\2\b,8;?UW") return buf.getvalue() @@ -609,10 +609,6 @@ def PLUS(self): return self.getToken(BaserowFormula.PLUS, 0) def MINUS(self): return self.getToken(BaserowFormula.MINUS, 0) - def AMP_AMP(self): - return self.getToken(BaserowFormula.AMP_AMP, 0) - def PIPE_PIPE(self): - return self.getToken(BaserowFormula.PIPE_PIPE, 0) def GT(self): return self.getToken(BaserowFormula.GT, 0) def LT(self): @@ -625,6 +621,10 @@ def EQUAL(self): return self.getToken(BaserowFormula.EQUAL, 0) def BANG_EQUAL(self): return self.getToken(BaserowFormula.BANG_EQUAL, 0) + def AMP_AMP(self): + return self.getToken(BaserowFormula.AMP_AMP, 0) + def PIPE_PIPE(self): + return self.getToken(BaserowFormula.PIPE_PIPE, 0) def enterRule(self, listener:ParseTreeListener): if hasattr( listener, "enterBinaryOp" ): @@ -703,7 +703,7 @@ def expr(self, _p:int=0): self.state = 21 self.ws_or_comment() self.state = 22 - self.expr(12) + self.expr(13) pass elif token in [BaserowFormula.OPEN_PAREN]: localctx = BaserowFormula.BracketsContext(self, localctx) @@ -802,7 +802,7 @@ def expr(self, _p:int=0): raise NoViableAltException(self) self._ctx.stop = self._input.LT(-1) - self.state = 82 + self.state = 85 self._errHandler.sync(self) _alt = self._interp.adaptivePredict(self._input,5,self._ctx) while _alt!=2 and _alt!=ATN.INVALID_ALT_NUMBER: @@ -810,16 +810,16 @@ def expr(self, _p:int=0): if self._parseListeners is not None: self.triggerExitRuleEvent() _prevctx = localctx - self.state = 80 + self.state = 83 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,4,self._ctx) if la_ == 1: localctx = BaserowFormula.BinaryOpContext(self, BaserowFormula.ExprContext(self, _parentctx, _parentState)) self.pushNewRecursionContext(localctx, _startState, self.RULE_expr) self.state = 63 - if not self.precpred(self._ctx, 9): + if not self.precpred(self._ctx, 10): from antlr4.error.Errors import FailedPredicateException - raise FailedPredicateException(self, "self.precpred(self._ctx, 9)") + raise FailedPredicateException(self, "self.precpred(self._ctx, 10)") self.state = 64 localctx.op = self._input.LT(1) _la = self._input.LA(1) @@ -829,16 +829,16 @@ def expr(self, _p:int=0): self._errHandler.reportMatch(self) self.consume() self.state = 65 - self.expr(10) + self.expr(11) pass elif la_ == 2: localctx = BaserowFormula.BinaryOpContext(self, BaserowFormula.ExprContext(self, _parentctx, _parentState)) self.pushNewRecursionContext(localctx, _startState, self.RULE_expr) self.state = 66 - if not self.precpred(self._ctx, 8): + if not self.precpred(self._ctx, 9): from antlr4.error.Errors import FailedPredicateException - raise FailedPredicateException(self, "self.precpred(self._ctx, 8)") + raise FailedPredicateException(self, "self.precpred(self._ctx, 9)") self.state = 67 localctx.op = self._input.LT(1) _la = self._input.LA(1) @@ -848,79 +848,86 @@ def expr(self, _p:int=0): self._errHandler.reportMatch(self) self.consume() self.state = 68 - self.expr(9) + self.expr(10) pass elif la_ == 3: localctx = BaserowFormula.BinaryOpContext(self, BaserowFormula.ExprContext(self, _parentctx, _parentState)) self.pushNewRecursionContext(localctx, _startState, self.RULE_expr) self.state = 69 - if not self.precpred(self._ctx, 7): + if not self.precpred(self._ctx, 8): from antlr4.error.Errors import FailedPredicateException - raise FailedPredicateException(self, "self.precpred(self._ctx, 7)") + raise FailedPredicateException(self, "self.precpred(self._ctx, 8)") self.state = 70 localctx.op = self._input.LT(1) _la = self._input.LA(1) - if not(_la==BaserowFormula.AMP_AMP or _la==BaserowFormula.PIPE_PIPE): + if not((((_la) & ~0x3f) == 0 and ((1 << _la) & ((1 << BaserowFormula.GT) | (1 << BaserowFormula.GTE) | (1 << BaserowFormula.LT) | (1 << BaserowFormula.LTE))) != 0)): localctx.op = self._errHandler.recoverInline(self) else: self._errHandler.reportMatch(self) self.consume() self.state = 71 - self.expr(8) + self.expr(9) pass elif la_ == 4: localctx = BaserowFormula.BinaryOpContext(self, BaserowFormula.ExprContext(self, _parentctx, _parentState)) self.pushNewRecursionContext(localctx, _startState, self.RULE_expr) self.state = 72 - if not self.precpred(self._ctx, 6): + if not self.precpred(self._ctx, 7): from antlr4.error.Errors import FailedPredicateException - raise FailedPredicateException(self, "self.precpred(self._ctx, 6)") + raise FailedPredicateException(self, "self.precpred(self._ctx, 7)") self.state = 73 localctx.op = self._input.LT(1) _la = self._input.LA(1) - if not((((_la) & ~0x3f) == 0 and ((1 << _la) & ((1 << BaserowFormula.GT) | (1 << BaserowFormula.GTE) | (1 << BaserowFormula.LT) | (1 << BaserowFormula.LTE))) != 0)): + if not(_la==BaserowFormula.BANG_EQUAL or _la==BaserowFormula.EQUAL): localctx.op = self._errHandler.recoverInline(self) else: self._errHandler.reportMatch(self) self.consume() self.state = 74 - self.expr(7) + self.expr(8) pass elif la_ == 5: localctx = BaserowFormula.BinaryOpContext(self, BaserowFormula.ExprContext(self, _parentctx, _parentState)) self.pushNewRecursionContext(localctx, _startState, self.RULE_expr) self.state = 75 - if not self.precpred(self._ctx, 5): + if not self.precpred(self._ctx, 6): from antlr4.error.Errors import FailedPredicateException - raise FailedPredicateException(self, "self.precpred(self._ctx, 5)") + raise FailedPredicateException(self, "self.precpred(self._ctx, 6)") self.state = 76 - localctx.op = self._input.LT(1) - _la = self._input.LA(1) - if not(_la==BaserowFormula.BANG_EQUAL or _la==BaserowFormula.EQUAL): - localctx.op = self._errHandler.recoverInline(self) - else: - self._errHandler.reportMatch(self) - self.consume() + localctx.op = self.match(BaserowFormula.AMP_AMP) self.state = 77 - self.expr(6) + self.expr(7) pass elif la_ == 6: - localctx = BaserowFormula.RightWhitespaceOrCommentsContext(self, BaserowFormula.ExprContext(self, _parentctx, _parentState)) + localctx = BaserowFormula.BinaryOpContext(self, BaserowFormula.ExprContext(self, _parentctx, _parentState)) self.pushNewRecursionContext(localctx, _startState, self.RULE_expr) self.state = 78 - if not self.precpred(self._ctx, 11): + if not self.precpred(self._ctx, 5): from antlr4.error.Errors import FailedPredicateException - raise FailedPredicateException(self, "self.precpred(self._ctx, 11)") + raise FailedPredicateException(self, "self.precpred(self._ctx, 5)") self.state = 79 + localctx.op = self.match(BaserowFormula.PIPE_PIPE) + self.state = 80 + self.expr(6) + pass + + elif la_ == 7: + localctx = BaserowFormula.RightWhitespaceOrCommentsContext(self, BaserowFormula.ExprContext(self, _parentctx, _parentState)) + self.pushNewRecursionContext(localctx, _startState, self.RULE_expr) + self.state = 81 + if not self.precpred(self._ctx, 12): + from antlr4.error.Errors import FailedPredicateException + raise FailedPredicateException(self, "self.precpred(self._ctx, 12)") + self.state = 82 self.ws_or_comment() pass - self.state = 84 + self.state = 87 self._errHandler.sync(self) _alt = self._interp.adaptivePredict(self._input,5,self._ctx) @@ -975,7 +982,7 @@ def ws_or_comment(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 85 + self.state = 88 _la = self._input.LA(1) if not((((_la) & ~0x3f) == 0 and ((1 << _la) & ((1 << BaserowFormula.BLOCK_COMMENT) | (1 << BaserowFormula.LINE_COMMENT) | (1 << BaserowFormula.WHITESPACE))) != 0)): self._errHandler.recoverInline(self) @@ -1027,7 +1034,7 @@ def func_name(self): self.enterRule(localctx, 6, self.RULE_func_name) try: self.enterOuterAlt(localctx, 1) - self.state = 87 + self.state = 90 self.identifier() except RecognitionException as re: localctx.exception = re @@ -1077,7 +1084,7 @@ def field_reference(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 89 + self.state = 92 _la = self._input.LA(1) if not(_la==BaserowFormula.SINGLEQ_STRING_LITERAL or _la==BaserowFormula.DOUBLEQ_STRING_LITERAL): self._errHandler.recoverInline(self) @@ -1132,7 +1139,7 @@ def identifier(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 91 + self.state = 94 _la = self._input.LA(1) if not(_la==BaserowFormula.IDENTIFIER or _la==BaserowFormula.IDENTIFIER_UNICODE): self._errHandler.recoverInline(self) @@ -1161,27 +1168,31 @@ def sempred(self, localctx:RuleContext, ruleIndex:int, predIndex:int): def expr_sempred(self, localctx:ExprContext, predIndex:int): if predIndex == 0: - return self.precpred(self._ctx, 9) + return self.precpred(self._ctx, 10) if predIndex == 1: - return self.precpred(self._ctx, 8) + return self.precpred(self._ctx, 9) if predIndex == 2: - return self.precpred(self._ctx, 7) + return self.precpred(self._ctx, 8) if predIndex == 3: - return self.precpred(self._ctx, 6) + return self.precpred(self._ctx, 7) if predIndex == 4: - return self.precpred(self._ctx, 5) + return self.precpred(self._ctx, 6) if predIndex == 5: - return self.precpred(self._ctx, 11) + return self.precpred(self._ctx, 5) + + + if predIndex == 6: + return self.precpred(self._ctx, 12) diff --git a/backend/src/baserow/core/migrations/0110_totpusedcode.py b/backend/src/baserow/core/migrations/0110_totpusedcode.py new file mode 100644 index 0000000000..d1b80664e0 --- /dev/null +++ b/backend/src/baserow/core/migrations/0110_totpusedcode.py @@ -0,0 +1,49 @@ +# Generated by Django 5.0.14 on 2026-01-07 10:53 + +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("core", "0109_userfile_deleted_at"), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name="TOTPUsedCode", + fields=[ + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("used_at", models.DateTimeField()), + ( + "code", + models.CharField(help_text="Hash of the used code", max_length=64), + ), + ( + "user", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="totp_used_codes", + to=settings.AUTH_USER_MODEL, + ), + ), + ], + options={ + "indexes": [ + models.Index( + fields=["user", "code"], name="totp_usedcode_user_code_idx" + ) + ], + }, + ), + ] diff --git a/backend/src/baserow/core/two_factor_auth/models.py b/backend/src/baserow/core/two_factor_auth/models.py index 1eb530217b..cd28e37935 100644 --- a/backend/src/baserow/core/two_factor_auth/models.py +++ b/backend/src/baserow/core/two_factor_auth/models.py @@ -57,6 +57,24 @@ def is_enabled(self): return self.enabled +class TOTPUsedCode(models.Model): + user = models.ForeignKey( + "auth.User", + on_delete=models.CASCADE, + related_name="totp_used_codes", + ) + used_at = models.DateTimeField() + code = models.CharField(max_length=64, help_text="Hash of the used code") + + class Meta: + indexes = [ + models.Index( + fields=["user", "code"], + name="totp_usedcode_user_code_idx", + ), + ] + + class TwoFactorAuthRecoveryCode(models.Model): user = models.ForeignKey( "auth.User", diff --git a/backend/src/baserow/core/two_factor_auth/registries.py b/backend/src/baserow/core/two_factor_auth/registries.py index 35fb939041..601a1e2a73 100644 --- a/backend/src/baserow/core/two_factor_auth/registries.py +++ b/backend/src/baserow/core/two_factor_auth/registries.py @@ -26,6 +26,7 @@ ) from baserow.core.two_factor_auth.models import ( TOTPAuthProviderModel, + TOTPUsedCode, TwoFactorAuthProviderModel, TwoFactorAuthRecoveryCode, ) @@ -134,6 +135,12 @@ def configure( backup_codes_plaintext = self.generate_backup_codes() self.store_backup_codes(provider, backup_codes_plaintext) + TOTPUsedCode.objects.create( + user=provider.user, + used_at=datetime.now(tz=timezone.utc), + code=hashlib.sha256(code.encode("utf-8")).hexdigest(), + ) + provider._backup_codes = backup_codes_plaintext return provider else: @@ -210,19 +217,36 @@ def verify(self, **kwargs) -> bool: recovery_code.delete() return True - provider = TwoFactorAuthProviderModel.objects.filter(user__email=email).first() + provider = ( + TwoFactorAuthProviderModel.objects.select_for_update(of=("self",)) + .filter(user__email=email) + .first() + ) if not provider: raise VerificationFailed totp = pyotp.TOTP(provider.specific.secret) + current_ts = datetime.now(tz=timezone.utc) + hashed_code = hashlib.sha256(code.encode("utf-8")).hexdigest() + + code_already_used = TOTPUsedCode.objects.filter( + user=provider.user, code=hashed_code + ).exists() - if totp.verify(code): + if not code_already_used and totp.verify(code): + TOTPUsedCode.objects.filter(user=provider.user).delete() + TOTPUsedCode.objects.create( + user=provider.user, + used_at=current_ts, + code=hashed_code, + ) return True else: raise VerificationFailed def disable(self, provider, user): TwoFactorAuthRecoveryCode.objects.filter(user=user).delete() + TOTPUsedCode.objects.filter(user=user).delete() provider.delete() diff --git a/backend/tests/baserow/api/two_factor_auth/test_two_factor_views.py b/backend/tests/baserow/api/two_factor_auth/test_two_factor_views.py index 8345b8d5fa..fbf46d8432 100644 --- a/backend/tests/baserow/api/two_factor_auth/test_two_factor_views.py +++ b/backend/tests/baserow/api/two_factor_auth/test_two_factor_views.py @@ -4,6 +4,7 @@ import pyotp import pytest +from freezegun import freeze_time from rest_framework.status import ( HTTP_200_OK, HTTP_204_NO_CONTENT, @@ -435,53 +436,55 @@ def test_verify_totp_view_missing_email(api_client, data_fixture): @pytest.mark.django_db def test_verify_totp_code_view(api_client, data_fixture): user, token = data_fixture.create_user_and_token() - provider = data_fixture.configure_totp(user) - - response = api_client.post( - reverse("api:user:token_auth"), - {"email": user.email, "password": "password"}, - format="json", - ) - response_json = response.json() - two_fa_token = response_json["token"] - - totp = pyotp.TOTP(provider.secret) - valid_code = totp.now() - - url = reverse("api:two_factor_auth:verify") - response = api_client.post( - url, - { - "type": "totp", - "email": user.email, - "code": valid_code, - }, - format="json", - HTTP_AUTHORIZATION=f"Bearer {two_fa_token}", - ) - - response_json = response.json() - assert response.status_code == HTTP_200_OK, response_json - assert response_json == { - "access_token": AnyStr(), - "active_licenses": {"instance_wide": {}, "per_workspace": {}}, - "permissions": AnyList(), - "refresh_token": AnyStr(), - "token": AnyStr(), - "user": { - "completed_guided_tours": [], - "completed_onboarding": False, - "email_notification_frequency": "instant", - "email_verified": False, - "first_name": user.first_name, - "id": user.id, - "is_staff": False, - "language": "en", - "username": user.email, - }, - "user_notifications": {"unread_count": 0}, - "user_session": AnyStr(), - } + with freeze_time("2020-02-01 00:00"): + provider = data_fixture.configure_totp(user) + + with freeze_time("2020-02-01 00:01"): + response = api_client.post( + reverse("api:user:token_auth"), + {"email": user.email, "password": "password"}, + format="json", + ) + response_json = response.json() + two_fa_token = response_json["token"] + + totp = pyotp.TOTP(provider.secret) + valid_code = totp.now() + + url = reverse("api:two_factor_auth:verify") + response = api_client.post( + url, + { + "type": "totp", + "email": user.email, + "code": valid_code, + }, + format="json", + HTTP_AUTHORIZATION=f"Bearer {two_fa_token}", + ) + + response_json = response.json() + assert response.status_code == HTTP_200_OK, response_json + assert response_json == { + "access_token": AnyStr(), + "active_licenses": {"instance_wide": {}, "per_workspace": {}}, + "permissions": AnyList(), + "refresh_token": AnyStr(), + "token": AnyStr(), + "user": { + "completed_guided_tours": [], + "completed_onboarding": False, + "email_notification_frequency": "instant", + "email_verified": False, + "first_name": user.first_name, + "id": user.id, + "is_staff": False, + "language": "en", + "username": user.email, + }, + "user_notifications": {"unread_count": 0}, + "user_session": AnyStr(), + } @pytest.mark.django_db diff --git a/backend/tests/baserow/core/two_factor_auth/test_two_factor_handler.py b/backend/tests/baserow/core/two_factor_auth/test_two_factor_handler.py index 1168b77637..72d382f705 100644 --- a/backend/tests/baserow/core/two_factor_auth/test_two_factor_handler.py +++ b/backend/tests/baserow/core/two_factor_auth/test_two_factor_handler.py @@ -2,6 +2,7 @@ import pyotp import pytest +from freezegun import freeze_time from baserow.core.two_factor_auth.exceptions import ( TwoFactorAuthCannotBeConfigured, @@ -144,9 +145,13 @@ def test_verify_no_provider(data_fixture): @pytest.mark.django_db def test_verify(data_fixture): - user = data_fixture.create_user(password="password") - provider = data_fixture.configure_totp(user) - totp = pyotp.TOTP(provider.secret) - code = totp.now() - - assert TwoFactorAuthHandler().verify("totp", email=user.email, code=code) is True + with freeze_time("2020-02-01 00:00"): + user = data_fixture.create_user(password="password") + provider = data_fixture.configure_totp(user) + totp = pyotp.TOTP(provider.secret) + + with freeze_time("2020-02-01 00:05"): + code = totp.now() + assert ( + TwoFactorAuthHandler().verify("totp", email=user.email, code=code) is True + ) diff --git a/backend/tests/baserow/core/two_factor_auth/test_two_factor_registries.py b/backend/tests/baserow/core/two_factor_auth/test_two_factor_registries.py index d9158b798b..2975fc0b2f 100644 --- a/backend/tests/baserow/core/two_factor_auth/test_two_factor_registries.py +++ b/backend/tests/baserow/core/two_factor_auth/test_two_factor_registries.py @@ -11,6 +11,7 @@ ) from baserow.core.two_factor_auth.models import ( TOTPAuthProviderModel, + TOTPUsedCode, TwoFactorAuthRecoveryCode, ) from baserow.core.two_factor_auth.registries import TOTPAuthProviderType @@ -66,6 +67,7 @@ def test_totp_configure_finish_configuration(data_fixture): assert provider.provisioning_qr_code == "" assert TOTPAuthProviderModel.objects.filter(user=user).count() == 1 assert TwoFactorAuthRecoveryCode.objects.filter(user=user).count() == 8 + assert TOTPUsedCode.objects.filter(user=user).count() == 1 @pytest.mark.django_db @@ -123,15 +125,20 @@ def test_generate_backup_codes(): @pytest.mark.django_db def test_verify_with_code(data_fixture): user = data_fixture.create_user() - provider = data_fixture.configure_totp(user) + with freeze_time("2020-02-01 00:00"): + provider = data_fixture.configure_totp(user) + assert TOTPUsedCode.objects.filter(user=user).count() == 1 + totp = pyotp.TOTP(provider.secret) - code = totp.now() - assert TOTPAuthProviderType().verify(email=user.email, code=code) + with freeze_time("2020-02-01 00:05"): + code = totp.now() + assert TOTPAuthProviderType().verify(email=user.email, code=code) + assert TOTPUsedCode.objects.filter(user=user).count() == 1 @pytest.mark.django_db -def test_verify_with_code_fails(data_fixture): +def test_verify_with_code_fails_wrong_code(data_fixture): user = data_fixture.create_user() data_fixture.configure_totp(user) @@ -139,6 +146,41 @@ def test_verify_with_code_fails(data_fixture): TOTPAuthProviderType().verify(email=user.email, code="1234567") +@pytest.mark.django_db +def test_verify_with_code_code_cannot_be_reused(data_fixture): + user = data_fixture.create_user() + user_2 = data_fixture.create_user() + with freeze_time("2020-02-01 00:00"): + provider = data_fixture.configure_totp(user) + provider_2 = data_fixture.configure_totp(user_2) + provider_2.secret = provider.secret + provider_2.save() + totp = pyotp.TOTP(provider.secret) + + with freeze_time("2020-02-01 00:05"): + code = totp.now() + + # first time the code is valid + assert TOTPAuthProviderType().verify(email=user.email, code=code) + + with pytest.raises(VerificationFailed): + TOTPAuthProviderType().verify(email=user.email, code=code) + + # another user with the same secret would not be + # affected + assert TOTPAuthProviderType().verify(email=user_2.email, code=code) + + with freeze_time("2020-02-01 00:10"): + code = totp.now() + + # user can use a new code from a different time window + assert TOTPAuthProviderType().verify(email=user.email, code=code) + + # older used codes are automatically deleted upon successful + # verification + assert TOTPUsedCode.objects.filter(user=user).count() == 1 + + @pytest.mark.django_db def test_verify_with_backup_code(data_fixture): user = data_fixture.create_user() @@ -169,9 +211,14 @@ def test_verify_no_provider(data_fixture): @pytest.mark.django_db def test_totp_disable(data_fixture): user = data_fixture.create_user() + user_2 = data_fixture.create_user() provider = data_fixture.configure_totp(user) + data_fixture.configure_totp(user_2) + assert TOTPUsedCode.objects.count() == 2 TOTPAuthProviderType().disable(provider, user) assert TOTPAuthProviderModel.objects.filter(user=user).count() == 0 assert TwoFactorAuthRecoveryCode.objects.filter(user=user).count() == 0 + assert TOTPUsedCode.objects.count() == 1 + assert TOTPUsedCode.objects.filter(user=user_2).count() == 1 diff --git a/changelog/entries/unreleased/bug/resolved_a_bug_in_the_baserow_formula_parser_which_prevented.json b/changelog/entries/unreleased/bug/resolved_a_bug_in_the_baserow_formula_parser_which_prevented.json new file mode 100644 index 0000000000..12b8c5af16 --- /dev/null +++ b/changelog/entries/unreleased/bug/resolved_a_bug_in_the_baserow_formula_parser_which_prevented.json @@ -0,0 +1,9 @@ +{ + "type": "bug", + "message": "Resolved a bug in the Baserow formula parser which prevented the OR operator (`||`) from being applied correctly.", + "issue_origin": "github", + "issue_number": null, + "domain": "core", + "bullet_points": [], + "created_at": "2025-12-30" +} \ No newline at end of file diff --git a/formula/BaserowFormula.g4 b/formula/BaserowFormula.g4 index 75b3d99285..9c357e0705 100644 --- a/formula/BaserowFormula.g4 +++ b/formula/BaserowFormula.g4 @@ -39,9 +39,10 @@ expr | OPEN_PAREN expr CLOSE_PAREN # Brackets | expr op=(SLASH | STAR) expr # BinaryOp | expr op=(PLUS | MINUS) expr # BinaryOp - | expr op=(AMP_AMP | PIPE_PIPE) expr # BinaryOp | expr op=(GT | LT | GTE | LTE) expr # BinaryOp | expr op=(EQUAL | BANG_EQUAL) expr # BinaryOp + | expr op=AMP_AMP expr # BinaryOp + | expr op=PIPE_PIPE expr # BinaryOp | FIELD OPEN_PAREN field_reference CLOSE_PAREN # FieldReference // FIELDBYID has been deprecated and should not be used, it is only included here // for backwards compatability. diff --git a/premium/backend/tests/baserow_premium_tests/license/test_license_handler.py b/premium/backend/tests/baserow_premium_tests/license/test_license_handler.py index 87e0fe7356..d8b7f6f06b 100644 --- a/premium/backend/tests/baserow_premium_tests/license/test_license_handler.py +++ b/premium/backend/tests/baserow_premium_tests/license/test_license_handler.py @@ -98,44 +98,46 @@ b"bL3jA==" ) VALID_PREMIUM_TEN_SEAT_TEN_APP_USER_LICENSE = ( - # id: "c26e4ef2-0492-4571-ad0d-49ca808c14b5" + # id: "a857b506-bf91-4a26-a716-085abfe0190f" # instance_id: "1" - b"eyJ2ZXJzaW9uIjogMSwgImlkIjogImMyNmU0ZWYyLTA0OTItNDU3MS1hZDBkLTQ5Y2E4MDhjMTRiNSIsI" - b"CJ2YWxpZF9mcm9tIjogIjIwMjUtMDItMDFUMDA6MDA6MDAiLCAidmFsaWRfdGhyb3VnaCI6ICIyMDI4LT" - b"AxLTAxVDIzOjU5OjU5IiwgInByb2R1Y3RfY29kZSI6ICJwcmVtaXVtIiwgInNlYXRzIjogMTAsICJhcHB" - b"saWNhdGlvbl91c2VycyI6IDEwLCAiaXNzdWVkX29uIjogIjIwMjUtMDItMTFUMTM6MzY6MjEuMDc1ODcz" + b"eyJ2ZXJzaW9uIjogMSwgImlkIjogImE4NTdiNTA2LWJmOTEtNGEyNi1hNzE2LTA4NWFiZmUwMTkwZiIsI" + b"CJ2YWxpZF9mcm9tIjogIjIwMjYtMDEtMDhUMDA6MDA6MDAiLCAidmFsaWRfdGhyb3VnaCI6ICIyMDUwLT" + b"AxLTA4VDIzOjU5OjU5IiwgInByb2R1Y3RfY29kZSI6ICJwcmVtaXVtIiwgInNlYXRzIjogMTAsICJhcHB" + b"saWNhdGlvbl91c2VycyI6IDEwLCAiaXNzdWVkX29uIjogIjIwMjYtMDEtMDhUMDk6NDY6NDguNzQzMTcz" b"IiwgImlzc3VlZF90b19lbWFpbCI6ICJwZXRlckBiYXNlcm93LmlvIiwgImlzc3VlZF90b19uYW1lIjogI" - b"lBldGVyIiwgImluc3RhbmNlX2lkIjogIjEifQ==.tEholymqZF9aoYUAPDvufzCLylDk92MVpb6J7XJEs" - b"k0zdgMdKwlrvCqNBpqtfDWJYJWKVxX4xk4NjTPBjdPbSRZM--kSL1uBa6djpLUU0XoXaOg74P39PW7gcQ" - b"qrsWbZRdDWn6fFePWQ4U9w83t5OvxflZE2Qd8tvWYAVbgKRZXbpkzKoJgMrGoC2QVBIqy6KA3FZxw5EVT" - b"KfMTkE34y8SsmTsvlDmLlt2fpkrFwM2Vpi4mE7GiY4nf5f4_8UHckpG8tqA-OK6KV4kPL_aTTLwdcZDL-" - b"aULpNydqXUfGMMgKzjq1L1cULsoZQc9ueFZBh8KmA2PEjw4i1o70-xePIA==" + b"lBldGVyIiwgImluc3RhbmNlX2lkIjogIjEifQ==.iRZWZQDQf2-pm0H8KSp_uw4OMwtKrlQ-LuZFVqgsi" + b"8yOFRVjKGnBaUC67yObYQAVfkRcGcPEQoZsx9_3ZC1K3Rxrj6lCbMl08BEhJbI3Td1I9Rbwd6L9t8b6iy" + b"LoCeObotB5BVUjBcU5gbQSW_vGULtzX-UzM8sjpUhJMio7kppl0N4b71FLFVjF2V92yD9meVNisoUCu6y" + b"XHPoAEBbo2I9OJ3q_BdTIOM-fp_CTai3icm9d3qz4eo8635V9y29yMwNpN6ZleBHgfuGkFID7K697EPxb" + b"9xav9CrZibRO6svmuMlEl3ILLVEB1Vjgi1DPzGMmHySbY4GyAkz7A6lAuw==" ) -VALID_PREMIUM_5_SEAT_15_APP_USER_LICENSE = ( - b"eyJ2ZXJzaW9uIjogMSwgImlkIjogImY4YjRlOTk1LTJhMmEtNDg0NS04ZWI1LWM2MjBiYzA5YTdiMiIsI" - b"CJ2YWxpZF9mcm9tIjogIjIwMjUtMDItMDFUMDA6MDA6MDAiLCAidmFsaWRfdGhyb3VnaCI6ICIyMDI2LT" - b"AxLTAxVDIzOjU5OjU5IiwgInByb2R1Y3RfY29kZSI6ICJwcmVtaXVtIiwgInNlYXRzIjogNSwgImFwcGx" - b"pY2F0aW9uX3VzZXJzIjogMTUsICJpc3N1ZWRfb24iOiAiMjAyNS0wMi0xN1QxMTo0NToyNC44NjM3NjQi" +VALID_PREMIUM_FIVE_SEAT_FIFTEEN_APP_USER_LICENSE = ( + # id: "f4fcf139-4b2f-438e-9377-fc02d8a51405" + # instance_id: "1" + b"eyJ2ZXJzaW9uIjogMSwgImlkIjogImY0ZmNmMTM5LTRiMmYtNDM4ZS05Mzc3LWZjMDJkOGE1MTQwNSIsI" + b"CJ2YWxpZF9mcm9tIjogIjIwMjYtMDEtMDhUMDA6MDA6MDAiLCAidmFsaWRfdGhyb3VnaCI6ICIyMDUwLT" + b"AxLTA4VDIzOjU5OjU5IiwgInByb2R1Y3RfY29kZSI6ICJwcmVtaXVtIiwgInNlYXRzIjogNSwgImFwcGx" + b"pY2F0aW9uX3VzZXJzIjogMTUsICJpc3N1ZWRfb24iOiAiMjAyNi0wMS0wOFQwOTo0ODoxNC4wMjQ4NTki" b"LCAiaXNzdWVkX3RvX2VtYWlsIjogInBldGVyQGJhc2Vyb3cuaW8iLCAiaXNzdWVkX3RvX25hbWUiOiAiU" - b"GV0ZXIiLCAiaW5zdGFuY2VfaWQiOiAiMSJ9.GsYLPV63FG5FAncOp6dyLysDqVSMR37C1zwTT-otZgGuu" - b"TpYg4aa9x-2ODonL9IAUmosyy6FZ1LcI4i8YdDyQ_rt-X_KhwR2S7Eotl6ZEepOYTbC7qKuG30szAKM6d" - b"4eL0unPB48pLJhSS_j745WgMn-4vUMmm6FTWaIPJaWFzwUjOp5zLgNpvvgkayzQ608XdYVjilVBcTlszj" - b"hxi00g0la2nMdCqDytZdJCn7XwAMA8itvSjYrWL1gMqTtPL6U92bJz97n8wQRBFW8kNKb2JTPfcbwozeg" - b"Vd44sPwBqWaA0wwpKyNs-Sa43FHcbQKIGG8A68hKQy2MG3EWHgLWTA==" + b"GV0ZXIiLCAiaW5zdGFuY2VfaWQiOiAiMSJ9.PQNYw9lTJrWNqGcIwPygE8kinldFg64c44yb1oXRhISxh" + b"LUs_zG2dwhG6j01XHw1psnkbwXFodT0AXbCJ5SA8QA1LRNXEV2DJce9Y1ve6De5LWh-BNnbA2g_sy0Tb5" + b"X89w7SmZWRrBWgFsgwIRj8ZCYJAVkNjPlTKyBArBM0syQYhg8DrCuWx-qeNUVahZzYYZJoAqf9Pv7X52X" + b"qVfffnhxaU872nr-5p_ctP9QhURlIRD9mzrDylFuNOwKqslpdknwoHZGwPBIgMNDV4fBLm3_VnIQDneNB" + b"ymX_rC2TJ_he-rt1MVWwnVUhu_e3UxY9DsF_EJ2apHD3IiNRdnYmHg==" ) VALID_ENTERPRISE_FIFTEEN_SEAT_FIFTEEN_APP_USER_LICENSE = ( - # id: "06b9bec3-d5d9-4286-be5a-c25b94188303" + # id: "ea098521-2b10-4f14-832f-ae3297b48c8f" # instance_id: "1" - b"eyJ2ZXJzaW9uIjogMSwgImlkIjogIjA2YjliZWMzLWQ1ZDktNDI4Ni1iZTVhLWMyNWI5NDE4ODMwMyIsI" - b"CJ2YWxpZF9mcm9tIjogIjIwMjUtMDItMDFUMDA6MDA6MDAiLCAidmFsaWRfdGhyb3VnaCI6ICIyMDI4LT" - b"AxLTAxVDIzOjU5OjU5IiwgInByb2R1Y3RfY29kZSI6ICJlbnRlcnByaXNlIiwgInNlYXRzIjogMTUsICJ" - b"hcHBsaWNhdGlvbl91c2VycyI6IDE1LCAiaXNzdWVkX29uIjogIjIwMjUtMDItMTFUMTM6MzU6MjYuODYy" - b"NTg3IiwgImlzc3VlZF90b19lbWFpbCI6ICJwZXRlckBiYXNlcm93LmlvIiwgImlzc3VlZF90b19uYW1lI" - b"jogIlBldGVyIiwgImluc3RhbmNlX2lkIjogIjEifQ==.u1ws8JSZHta15GVqiUdQRb592aeIuAUxSNMDm" - b"_WAY1rSFzeY74MLhl7aQ3ZB5JalUwuT8Bi1PqCBqiSSVJGdF5pL4u25Gwn10mNDvfXmRh34DvV7ZIYdpV" - b"C_WiPOkeojoXtawuNmIzePON1pAv6TfG9Qq_57vSshht49TiG2PTYGdeeZa9sbrP589dhkIk0UY6Z6aCZ" - b"voGAXz0rbrsS6lQUFqkYdBgA4LpgsrWWjLRxKdmy64CYj1k37ERtU8w-uauhYW3IUHDmDiZQYjNrL7g7q" - b"Elk5YJBqjseMM_J4VkgULax1TDyG-q114UKCeCrCFA4pqsbxvGJ41-Le_-JOEg==" + b"eyJ2ZXJzaW9uIjogMSwgImlkIjogImVhMDk4NTIxLTJiMTAtNGYxNC04MzJmLWFlMzI5N2I0OGM4ZiIsI" + b"CJ2YWxpZF9mcm9tIjogIjIwMjYtMDEtMDhUMDA6MDA6MDAiLCAidmFsaWRfdGhyb3VnaCI6ICIyMDUwLT" + b"AxLTA4VDIzOjU5OjU5IiwgInByb2R1Y3RfY29kZSI6ICJlbnRlcnByaXNlIiwgInNlYXRzIjogMTUsICJ" + b"hcHBsaWNhdGlvbl91c2VycyI6IDE1LCAiaXNzdWVkX29uIjogIjIwMjYtMDEtMDhUMDk6NDg6NTcuMjI5" + b"NjAyIiwgImlzc3VlZF90b19lbWFpbCI6ICJwZXRlckBiYXNlcm93LmlvIiwgImlzc3VlZF90b19uYW1lI" + b"jogIlBldGVyIiwgImluc3RhbmNlX2lkIjogIjEifQ==.teZZNBx9shRZlnAOZJCKR4cx8OCZc2IlMlgDi" + b"zNYCO-dlJQxM_4_k06m_OqHtdEfrio_lVc7YJAHSE0yM1dELUOTc0pPgHE6sWFRO0NxwyTUN4KdD6H3B5" + b"pN7hpBAnNJVThjLaTAhbYil32U1FumHBa0pyOhxWruRy4dbW9SAsI0oiIW1CUvYhWG_VMEasfPOxB26JU" + b"RtDX3SIP6li4ES4ppehQ-Cv-JudQcc1a2gNkL3sXxIG6Mguu01p8aMKWpV7suET35UdxxhcVTBTMJvwG7" + b"IBQkIlED0RySD41484QdOfxh3ESg_WtoM4dxpHu5EVkzsSIDs5NkjWoK4n9gzg==" ) INVALID_SIGNATURE_LICENSE = ( b"eyJ2ZXJzaW9uIjogMSwgImlkIjogMSwgInZhbGlkX2Zyb20iOiAiMjAyMS0wOC0yOVQxOTo1NDoxMi4w" @@ -161,7 +163,7 @@ b"CVof8RBUq1DgMcDKEGE7WRHYDVP1QugBjf4GZlvIE4ZVr3tKr0aKPX8nuNVhbQeudCW8tnturmxevpRN" b"vLS5ETSQzJoP46cGuw0HUV20P4SnvQP_NRd5zifgllJqsUw==" ) -INVALID_PREMIUM_FIVE_SEAT_10_APP_USER_EXPIRED_LICENSE = ( +INVALID_PREMIUM_FIVE_SEAT_TEN_APP_USER_EXPIRED_LICENSE = ( b"eyJ2ZXJzaW9uIjogMSwgImlkIjogIjkzZDExODYwLTU1Y2UtNDJhYy05NGI5LTY0YTlhMTBiNzI3MiIsI" b"CJ2YWxpZF9mcm9tIjogIjIwMjUtMDItMDFUMDA6MDA6MDAiLCAidmFsaWRfdGhyb3VnaCI6ICIyMDI1LT" b"AyLTA4VDIzOjU5OjU5IiwgInByb2R1Y3RfY29kZSI6ICJwcmVtaXVtIiwgInNlYXRzIjogNSwgImFwcGx" @@ -620,13 +622,13 @@ def test_decode_license_with_valid_license(): VALID_ENTERPRISE_FIFTEEN_SEAT_FIFTEEN_APP_USER_LICENSE ) == { "version": 1, - "id": "06b9bec3-d5d9-4286-be5a-c25b94188303", - "valid_from": "2025-02-01T00:00:00", - "valid_through": "2028-01-01T23:59:59", + "id": "ea098521-2b10-4f14-832f-ae3297b48c8f", + "valid_from": "2026-01-08T00:00:00", + "valid_through": "2050-01-08T23:59:59", "product_code": "enterprise", "seats": 15, "application_users": 15, - "issued_on": "2025-02-11T13:35:26.862587", + "issued_on": "2026-01-08T09:48:57.229602", "issued_to_email": "peter@baserow.io", "issued_to_name": "Peter", "instance_id": "1", @@ -635,13 +637,13 @@ def test_decode_license_with_valid_license(): VALID_PREMIUM_TEN_SEAT_TEN_APP_USER_LICENSE ) == { "version": 1, - "id": "c26e4ef2-0492-4571-ad0d-49ca808c14b5", - "valid_from": "2025-02-01T00:00:00", - "valid_through": "2028-01-01T23:59:59", + "id": "a857b506-bf91-4a26-a716-085abfe0190f", + "valid_from": "2026-01-08T00:00:00", + "valid_through": "2050-01-08T23:59:59", "product_code": "premium", "seats": 10, "application_users": 10, - "issued_on": "2025-02-11T13:36:21.075873", + "issued_on": "2026-01-08T09:46:48.743173", "issued_to_email": "peter@baserow.io", "issued_to_name": "Peter", "instance_id": "1", @@ -1163,7 +1165,7 @@ def test_premium_license_builder_usage_license_extra_info( # users available, but now our application users taken is 30. mock_aggregate_user_source_counts.return_value = 30 second_license = premium_data_fixture.create_premium_license( - license=VALID_PREMIUM_5_SEAT_15_APP_USER_LICENSE.decode() + license=VALID_PREMIUM_FIVE_SEAT_FIFTEEN_APP_USER_LICENSE.decode() ) with local_cache.context(): @@ -1190,7 +1192,7 @@ def test_premium_license_builder_usage_license_extra_info( with local_cache.context(): # An expired license reports an application user usage of 0. expired_license = premium_data_fixture.create_premium_license( - license=INVALID_PREMIUM_FIVE_SEAT_10_APP_USER_EXPIRED_LICENSE.decode() + license=INVALID_PREMIUM_FIVE_SEAT_TEN_APP_USER_EXPIRED_LICENSE.decode() ) assert LicenseHandler.collect_extra_license_info(expired_license) == { "id": expired_license.license_id, diff --git a/premium/backend/tests/baserow_premium_tests/license/test_license_types.py b/premium/backend/tests/baserow_premium_tests/license/test_license_types.py index 5734c3e809..39cadd49a9 100644 --- a/premium/backend/tests/baserow_premium_tests/license/test_license_types.py +++ b/premium/backend/tests/baserow_premium_tests/license/test_license_types.py @@ -5,43 +5,44 @@ import pytest VALID_FIRST_PREMIUM_5_SEAT_10_APP_USER_LICENSE = ( - b"eyJ2ZXJzaW9uIjogMSwgImlkIjogIjhiZmMwNzA1LWUwZGEtNGNkNy1hMWE0LWNjNDNiYjViMTE4OCIsI" - b"CJ2YWxpZF9mcm9tIjogIjIwMjUtMDItMDFUMDA6MDA6MDAiLCAidmFsaWRfdGhyb3VnaCI6ICIyMDI2LT" - b"AxLTAxVDIzOjU5OjU5IiwgInByb2R1Y3RfY29kZSI6ICJwcmVtaXVtIiwgInNlYXRzIjogNSwgImFwcGx" - b"pY2F0aW9uX3VzZXJzIjogMTAsICJpc3N1ZWRfb24iOiAiMjAyNS0wMi0xN1QxMTo0NToxOS44NDI3OTYi" + b"eyJ2ZXJzaW9uIjogMSwgImlkIjogImM2MmQwNzdhLTg3YmEtNGM1ZS05Y2M5LTRhN2NhYzZiMmNjNyIsI" + b"CJ2YWxpZF9mcm9tIjogIjIwMjYtMDEtMDhUMDA6MDA6MDAiLCAidmFsaWRfdGhyb3VnaCI6ICIyMDUwLT" + b"AxLTA4VDIzOjU5OjU5IiwgInByb2R1Y3RfY29kZSI6ICJwcmVtaXVtIiwgInNlYXRzIjogNSwgImFwcGx" + b"pY2F0aW9uX3VzZXJzIjogMTAsICJpc3N1ZWRfb24iOiAiMjAyNi0wMS0wOFQwOToyNjo0OS43NzE3MTci" b"LCAiaXNzdWVkX3RvX2VtYWlsIjogInBldGVyQGJhc2Vyb3cuaW8iLCAiaXNzdWVkX3RvX25hbWUiOiAiU" - b"GV0ZXIiLCAiaW5zdGFuY2VfaWQiOiAiMSJ9.oSV2phIkZHsVXsQN1X2E4hKab7_-JLaz2b93M3GHx3zvt" - b"_XTdeZRd-VK8ZvFdFDLh1LkKa4NAs8tSg8H1jN1xprkr-VFGA_-_owZrn59jK7UBOrd8p1WZur36ud5uG" - b"DRsyw-yLmBhuFj27jE_3GZz-93xPnrDATjbT9NrXfrOggsyhn36tNLqydmrdpu45KdLD1SRrm7zcKaG8L" - b"CHnlgSAd8md0923z7xf5vpTtB1rdJKUGj8kpjK7bxNojgmzZasGG424YbmSmk0B6yLvm18hIwv7_2Telk" - b"hs8huMXL7HHDlEK2O7GmmCBoWT0ACNmcBhq4OcZ0K1pPX7MXvU3RNQ==" + b"GV0ZXIiLCAiaW5zdGFuY2VfaWQiOiAiMSJ9.WmuaTFYMXJF0DrJQVWZDUFRPMllYhuprbzAflf53_Etjc" + b"haiHztKAQrEM5OwOKHLuVI-V1wuiQOP2ClP339w_bruzhLjIPKhuo6rBsllZvRyfs0axo8bDJ5Ff0xKWz" + b"BEjOgndVKcFeWVcnhl3OE2cXQYMqcOapuaG3UTbwHa3G8n4TVYDv0Xtztfam9U9Tub8C_n9KBDbswS31Y" + b"XzBQW86xU-9uIvjq1rLbmSIto3FbSGNNR8GuEuQXe0LuoS5iLf_9B3qF8Rrn8cml5N_2c78K_NA0olHqy" + b"-ShSx0axC5OrwcpWhAwXccpB0X9VutE97_WtEikiQqhhCeNiyEy2_w==" ) VALID_SECOND_PREMIUM_5_SEAT_15_APP_USER_LICENSE = ( - b"eyJ2ZXJzaW9uIjogMSwgImlkIjogImY4YjRlOTk1LTJhMmEtNDg0NS04ZWI1LWM2MjBiYzA5YTdiMiIsI" - b"CJ2YWxpZF9mcm9tIjogIjIwMjUtMDItMDFUMDA6MDA6MDAiLCAidmFsaWRfdGhyb3VnaCI6ICIyMDI2LT" - b"AxLTAxVDIzOjU5OjU5IiwgInByb2R1Y3RfY29kZSI6ICJwcmVtaXVtIiwgInNlYXRzIjogNSwgImFwcGx" - b"pY2F0aW9uX3VzZXJzIjogMTUsICJpc3N1ZWRfb24iOiAiMjAyNS0wMi0xN1QxMTo0NToyNC44NjM3NjQi" + b"eyJ2ZXJzaW9uIjogMSwgImlkIjogImZmZjMyYTUwLTc4MzMtNDBmZS1iZjJhLTJjYWZkOWY0ZDdkMCIsI" + b"CJ2YWxpZF9mcm9tIjogIjIwMjYtMDEtMDhUMDA6MDA6MDAiLCAidmFsaWRfdGhyb3VnaCI6ICIyMDUwLT" + b"AxLTA4VDIzOjU5OjU5IiwgInByb2R1Y3RfY29kZSI6ICJwcmVtaXVtIiwgInNlYXRzIjogNSwgImFwcGx" + b"pY2F0aW9uX3VzZXJzIjogMTUsICJpc3N1ZWRfb24iOiAiMjAyNi0wMS0wOFQwOToyODowNC41MDQ3MDMi" b"LCAiaXNzdWVkX3RvX2VtYWlsIjogInBldGVyQGJhc2Vyb3cuaW8iLCAiaXNzdWVkX3RvX25hbWUiOiAiU" - b"GV0ZXIiLCAiaW5zdGFuY2VfaWQiOiAiMSJ9.GsYLPV63FG5FAncOp6dyLysDqVSMR37C1zwTT-otZgGuu" - b"TpYg4aa9x-2ODonL9IAUmosyy6FZ1LcI4i8YdDyQ_rt-X_KhwR2S7Eotl6ZEepOYTbC7qKuG30szAKM6d" - b"4eL0unPB48pLJhSS_j745WgMn-4vUMmm6FTWaIPJaWFzwUjOp5zLgNpvvgkayzQ608XdYVjilVBcTlszj" - b"hxi00g0la2nMdCqDytZdJCn7XwAMA8itvSjYrWL1gMqTtPL6U92bJz97n8wQRBFW8kNKb2JTPfcbwozeg" - b"Vd44sPwBqWaA0wwpKyNs-Sa43FHcbQKIGG8A68hKQy2MG3EWHgLWTA==" + b"GV0ZXIiLCAiaW5zdGFuY2VfaWQiOiAiMSJ9.uAm7eoMn7LKA-edd10LISe0dkh_ocn-StgqNtGO5rEJRW" + b"Onwd5a7Nh611NMTq_yI0vSwZ4GjeSxHlkJv-GHZLB3sjdQ5BP6c7g1EFmbN4r4Usue0h1BFDRhLlSdNJa" + b"zU9nqo3AD6ym_j7cgIbdtNqIkhum9H1Cs73Gyaqh1Va_oQeLQRq7tTc3N8BlzuC6nIU68Cme8-oUhA-NI" + b"AaID2LDHRipWGKAv8EMbK45WOhrqNwesDOXHvwK8jDLKj2yO2QMN6BY1FxHSjd_kXxwlrzYTUov8sZpnt" + b"fORFtQyO_RfhBkq1HUjs_O44DObkxYqProsWM45LfasCdFcRZPDaLQ==" ) VALID_ENTERPRISE_15_SEAT_15_APP_USER_LICENSE = ( - b"eyJ2ZXJzaW9uIjogMSwgImlkIjogIjA2YjliZWMzLWQ1ZDktNDI4Ni1iZTVhLWMyNWI5NDE4ODMwMyIsI" - b"CJ2YWxpZF9mcm9tIjogIjIwMjUtMDItMDFUMDA6MDA6MDAiLCAidmFsaWRfdGhyb3VnaCI6ICIyMDI4LT" - b"AxLTAxVDIzOjU5OjU5IiwgInByb2R1Y3RfY29kZSI6ICJlbnRlcnByaXNlIiwgInNlYXRzIjogMTUsICJ" - b"hcHBsaWNhdGlvbl91c2VycyI6IDE1LCAiaXNzdWVkX29uIjogIjIwMjUtMDItMTFUMTM6MzU6MjYuODYy" - b"NTg3IiwgImlzc3VlZF90b19lbWFpbCI6ICJwZXRlckBiYXNlcm93LmlvIiwgImlzc3VlZF90b19uYW1lI" - b"jogIlBldGVyIiwgImluc3RhbmNlX2lkIjogIjEifQ==.u1ws8JSZHta15GVqiUdQRb592aeIuAUxSNMDm" - b"_WAY1rSFzeY74MLhl7aQ3ZB5JalUwuT8Bi1PqCBqiSSVJGdF5pL4u25Gwn10mNDvfXmRh34DvV7ZIYdpV" - b"C_WiPOkeojoXtawuNmIzePON1pAv6TfG9Qq_57vSshht49TiG2PTYGdeeZa9sbrP589dhkIk0UY6Z6aCZ" - b"voGAXz0rbrsS6lQUFqkYdBgA4LpgsrWWjLRxKdmy64CYj1k37ERtU8w-uauhYW3IUHDmDiZQYjNrL7g7q" - b"Elk5YJBqjseMM_J4VkgULax1TDyG-q114UKCeCrCFA4pqsbxvGJ41-Le_-JOEg==" + b"eyJ2ZXJzaW9uIjogMSwgImlkIjogImVhMDk4NTIxLTJiMTAtNGYxNC04MzJmLWFlMzI5N2I0OGM4ZiIsI" + b"CJ2YWxpZF9mcm9tIjogIjIwMjYtMDEtMDhUMDA6MDA6MDAiLCAidmFsaWRfdGhyb3VnaCI6ICIyMDUwLT" + b"AxLTA4VDIzOjU5OjU5IiwgInByb2R1Y3RfY29kZSI6ICJlbnRlcnByaXNlIiwgInNlYXRzIjogMTUsICJ" + b"hcHBsaWNhdGlvbl91c2VycyI6IDE1LCAiaXNzdWVkX29uIjogIjIwMjYtMDEtMDhUMDk6Mjk6MTcuOTcx" + b"NzUyIiwgImlzc3VlZF90b19lbWFpbCI6ICJwZXRlckBiYXNlcm93LmlvIiwgImlzc3VlZF90b19uYW1lI" + b"jogIlBldGVyIiwgImluc3RhbmNlX2lkIjogIjEifQ==.ogM9TYtnWLM_fkdmMFZvaWGDFNGvTkzktIvgk" + b"NCkmP1E9M_XWwYLdb4A-dMoG_5YTH1NixlxsGZN-EGRQ9o04NsouvXJ0S70aCVh2PZ35k0qyNw5tNN5nC" + b"luJav7vBXkUB4z3c1qPsoArQLr1TMNBG3I8duB8Kjd7dKi2z1rtBSmJZP6BrqSR4EfHWdj3Pk5x9fqfFl" + b"33Ubio1Xp_xHuApWXxEIp-eHjMmBe2eZ_dd-rvO7VA6wGpCaqaZKOkHxajS3SHKXjtB1rwnUs84up0r5k" + b"MF5eJHgjOzN-9lIv5zIxH09BBnQPB70ZYlHurk0LiJu8rfWu3OtwRQG0otM2xA==" ) + VALID_ENTERPRISE_FIVE_SEAT_LICENSE = ( b"eyJ2ZXJzaW9uIjogMSwgImlkIjogIjNmMDE2OGFmLWFmYWYtNDQyNi04OTZiLWIzODgzOTEwNzZlNyIsI" b"CJ2YWxpZF9mcm9tIjogIjIwMjEtMDEtMDFUMDA6MDA6MDAiLCAidmFsaWRfdGhyb3VnaCI6ICIyMDIxLT" diff --git a/web-frontend/modules/core/formula/parser/generated/BaserowFormula.interp b/web-frontend/modules/core/formula/parser/generated/BaserowFormula.interp index 2867b10bf2..e863cab988 100644 --- a/web-frontend/modules/core/formula/parser/generated/BaserowFormula.interp +++ b/web-frontend/modules/core/formula/parser/generated/BaserowFormula.interp @@ -180,4 +180,4 @@ identifier atn: -[3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 3, 85, 96, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 3, 2, 3, 2, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 3, 45, 10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 7, 3, 55, 10, 3, 12, 3, 14, 3, 58, 11, 3, 5, 3, 60, 10, 3, 3, 3, 3, 3, 5, 3, 64, 10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 7, 3, 83, 10, 3, 12, 3, 14, 3, 86, 11, 3, 3, 4, 3, 4, 3, 5, 3, 5, 3, 6, 3, 6, 3, 7, 3, 7, 3, 7, 2, 3, 4, 8, 2, 4, 6, 8, 10, 12, 2, 11, 3, 2, 6, 7, 4, 2, 16, 16, 75, 75, 4, 2, 63, 63, 69, 69, 4, 2, 32, 32, 66, 66, 4, 2, 43, 44, 54, 55, 4, 2, 39, 39, 41, 41, 3, 2, 3, 5, 3, 2, 27, 28, 3, 2, 29, 30, 2, 108, 2, 14, 3, 2, 2, 2, 4, 63, 3, 2, 2, 2, 6, 87, 3, 2, 2, 2, 8, 89, 3, 2, 2, 2, 10, 91, 3, 2, 2, 2, 12, 93, 3, 2, 2, 2, 14, 15, 5, 4, 3, 2, 15, 16, 7, 2, 2, 3, 16, 3, 3, 2, 2, 2, 17, 18, 8, 3, 1, 2, 18, 64, 7, 27, 2, 2, 19, 64, 7, 28, 2, 2, 20, 64, 7, 24, 2, 2, 21, 64, 7, 23, 2, 2, 22, 64, 9, 2, 2, 2, 23, 24, 5, 6, 4, 2, 24, 25, 5, 4, 3, 14, 25, 64, 3, 2, 2, 2, 26, 27, 7, 17, 2, 2, 27, 28, 5, 4, 3, 2, 28, 29, 7, 18, 2, 2, 29, 64, 3, 2, 2, 2, 30, 31, 7, 8, 2, 2, 31, 32, 7, 17, 2, 2, 32, 33, 5, 10, 6, 2, 33, 34, 7, 18, 2, 2, 34, 64, 3, 2, 2, 2, 35, 36, 7, 9, 2, 2, 36, 37, 7, 17, 2, 2, 37, 38, 7, 24, 2, 2, 38, 64, 7, 18, 2, 2, 39, 40, 7, 10, 2, 2, 40, 41, 7, 17, 2, 2, 41, 42, 5, 10, 6, 2, 42, 44, 7, 11, 2, 2, 43, 45, 7, 5, 2, 2, 44, 43, 3, 2, 2, 2, 44, 45, 3, 2, 2, 2, 45, 46, 3, 2, 2, 2, 46, 47, 5, 10, 6, 2, 47, 48, 7, 18, 2, 2, 48, 64, 3, 2, 2, 2, 49, 50, 5, 8, 5, 2, 50, 59, 7, 17, 2, 2, 51, 56, 5, 4, 3, 2, 52, 53, 7, 11, 2, 2, 53, 55, 5, 4, 3, 2, 54, 52, 3, 2, 2, 2, 55, 58, 3, 2, 2, 2, 56, 54, 3, 2, 2, 2, 56, 57, 3, 2, 2, 2, 57, 60, 3, 2, 2, 2, 58, 56, 3, 2, 2, 2, 59, 51, 3, 2, 2, 2, 59, 60, 3, 2, 2, 2, 60, 61, 3, 2, 2, 2, 61, 62, 7, 18, 2, 2, 62, 64, 3, 2, 2, 2, 63, 17, 3, 2, 2, 2, 63, 19, 3, 2, 2, 2, 63, 20, 3, 2, 2, 2, 63, 21, 3, 2, 2, 2, 63, 22, 3, 2, 2, 2, 63, 23, 3, 2, 2, 2, 63, 26, 3, 2, 2, 2, 63, 30, 3, 2, 2, 2, 63, 35, 3, 2, 2, 2, 63, 39, 3, 2, 2, 2, 63, 49, 3, 2, 2, 2, 64, 84, 3, 2, 2, 2, 65, 66, 12, 11, 2, 2, 66, 67, 9, 3, 2, 2, 67, 83, 5, 4, 3, 12, 68, 69, 12, 10, 2, 2, 69, 70, 9, 4, 2, 2, 70, 83, 5, 4, 3, 11, 71, 72, 12, 9, 2, 2, 72, 73, 9, 5, 2, 2, 73, 83, 5, 4, 3, 10, 74, 75, 12, 8, 2, 2, 75, 76, 9, 6, 2, 2, 76, 83, 5, 4, 3, 9, 77, 78, 12, 7, 2, 2, 78, 79, 9, 7, 2, 2, 79, 83, 5, 4, 3, 8, 80, 81, 12, 13, 2, 2, 81, 83, 5, 6, 4, 2, 82, 65, 3, 2, 2, 2, 82, 68, 3, 2, 2, 2, 82, 71, 3, 2, 2, 2, 82, 74, 3, 2, 2, 2, 82, 77, 3, 2, 2, 2, 82, 80, 3, 2, 2, 2, 83, 86, 3, 2, 2, 2, 84, 82, 3, 2, 2, 2, 84, 85, 3, 2, 2, 2, 85, 5, 3, 2, 2, 2, 86, 84, 3, 2, 2, 2, 87, 88, 9, 8, 2, 2, 88, 7, 3, 2, 2, 2, 89, 90, 5, 12, 7, 2, 90, 9, 3, 2, 2, 2, 91, 92, 9, 9, 2, 2, 92, 11, 3, 2, 2, 2, 93, 94, 9, 10, 2, 2, 94, 13, 3, 2, 2, 2, 8, 44, 56, 59, 63, 82, 84] \ No newline at end of file +[3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 3, 85, 99, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 3, 2, 3, 2, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 3, 45, 10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 7, 3, 55, 10, 3, 12, 3, 14, 3, 58, 11, 3, 5, 3, 60, 10, 3, 3, 3, 3, 3, 5, 3, 64, 10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 7, 3, 86, 10, 3, 12, 3, 14, 3, 89, 11, 3, 3, 4, 3, 4, 3, 5, 3, 5, 3, 6, 3, 6, 3, 7, 3, 7, 3, 7, 2, 3, 4, 8, 2, 4, 6, 8, 10, 12, 2, 10, 3, 2, 6, 7, 4, 2, 16, 16, 75, 75, 4, 2, 63, 63, 69, 69, 4, 2, 43, 44, 54, 55, 4, 2, 39, 39, 41, 41, 3, 2, 3, 5, 3, 2, 27, 28, 3, 2, 29, 30, 2, 112, 2, 14, 3, 2, 2, 2, 4, 63, 3, 2, 2, 2, 6, 90, 3, 2, 2, 2, 8, 92, 3, 2, 2, 2, 10, 94, 3, 2, 2, 2, 12, 96, 3, 2, 2, 2, 14, 15, 5, 4, 3, 2, 15, 16, 7, 2, 2, 3, 16, 3, 3, 2, 2, 2, 17, 18, 8, 3, 1, 2, 18, 64, 7, 27, 2, 2, 19, 64, 7, 28, 2, 2, 20, 64, 7, 24, 2, 2, 21, 64, 7, 23, 2, 2, 22, 64, 9, 2, 2, 2, 23, 24, 5, 6, 4, 2, 24, 25, 5, 4, 3, 15, 25, 64, 3, 2, 2, 2, 26, 27, 7, 17, 2, 2, 27, 28, 5, 4, 3, 2, 28, 29, 7, 18, 2, 2, 29, 64, 3, 2, 2, 2, 30, 31, 7, 8, 2, 2, 31, 32, 7, 17, 2, 2, 32, 33, 5, 10, 6, 2, 33, 34, 7, 18, 2, 2, 34, 64, 3, 2, 2, 2, 35, 36, 7, 9, 2, 2, 36, 37, 7, 17, 2, 2, 37, 38, 7, 24, 2, 2, 38, 64, 7, 18, 2, 2, 39, 40, 7, 10, 2, 2, 40, 41, 7, 17, 2, 2, 41, 42, 5, 10, 6, 2, 42, 44, 7, 11, 2, 2, 43, 45, 7, 5, 2, 2, 44, 43, 3, 2, 2, 2, 44, 45, 3, 2, 2, 2, 45, 46, 3, 2, 2, 2, 46, 47, 5, 10, 6, 2, 47, 48, 7, 18, 2, 2, 48, 64, 3, 2, 2, 2, 49, 50, 5, 8, 5, 2, 50, 59, 7, 17, 2, 2, 51, 56, 5, 4, 3, 2, 52, 53, 7, 11, 2, 2, 53, 55, 5, 4, 3, 2, 54, 52, 3, 2, 2, 2, 55, 58, 3, 2, 2, 2, 56, 54, 3, 2, 2, 2, 56, 57, 3, 2, 2, 2, 57, 60, 3, 2, 2, 2, 58, 56, 3, 2, 2, 2, 59, 51, 3, 2, 2, 2, 59, 60, 3, 2, 2, 2, 60, 61, 3, 2, 2, 2, 61, 62, 7, 18, 2, 2, 62, 64, 3, 2, 2, 2, 63, 17, 3, 2, 2, 2, 63, 19, 3, 2, 2, 2, 63, 20, 3, 2, 2, 2, 63, 21, 3, 2, 2, 2, 63, 22, 3, 2, 2, 2, 63, 23, 3, 2, 2, 2, 63, 26, 3, 2, 2, 2, 63, 30, 3, 2, 2, 2, 63, 35, 3, 2, 2, 2, 63, 39, 3, 2, 2, 2, 63, 49, 3, 2, 2, 2, 64, 87, 3, 2, 2, 2, 65, 66, 12, 12, 2, 2, 66, 67, 9, 3, 2, 2, 67, 86, 5, 4, 3, 13, 68, 69, 12, 11, 2, 2, 69, 70, 9, 4, 2, 2, 70, 86, 5, 4, 3, 12, 71, 72, 12, 10, 2, 2, 72, 73, 9, 5, 2, 2, 73, 86, 5, 4, 3, 11, 74, 75, 12, 9, 2, 2, 75, 76, 9, 6, 2, 2, 76, 86, 5, 4, 3, 10, 77, 78, 12, 8, 2, 2, 78, 79, 7, 32, 2, 2, 79, 86, 5, 4, 3, 9, 80, 81, 12, 7, 2, 2, 81, 82, 7, 66, 2, 2, 82, 86, 5, 4, 3, 8, 83, 84, 12, 14, 2, 2, 84, 86, 5, 6, 4, 2, 85, 65, 3, 2, 2, 2, 85, 68, 3, 2, 2, 2, 85, 71, 3, 2, 2, 2, 85, 74, 3, 2, 2, 2, 85, 77, 3, 2, 2, 2, 85, 80, 3, 2, 2, 2, 85, 83, 3, 2, 2, 2, 86, 89, 3, 2, 2, 2, 87, 85, 3, 2, 2, 2, 87, 88, 3, 2, 2, 2, 88, 5, 3, 2, 2, 2, 89, 87, 3, 2, 2, 2, 90, 91, 9, 7, 2, 2, 91, 7, 3, 2, 2, 2, 92, 93, 5, 12, 7, 2, 93, 9, 3, 2, 2, 2, 94, 95, 9, 8, 2, 2, 95, 11, 3, 2, 2, 2, 96, 97, 9, 9, 2, 2, 97, 13, 3, 2, 2, 2, 8, 44, 56, 59, 63, 85, 87] \ No newline at end of file diff --git a/web-frontend/modules/core/formula/parser/generated/BaserowFormula.js b/web-frontend/modules/core/formula/parser/generated/BaserowFormula.js index 8f5c2a3f57..0e133cd390 100644 --- a/web-frontend/modules/core/formula/parser/generated/BaserowFormula.js +++ b/web-frontend/modules/core/formula/parser/generated/BaserowFormula.js @@ -6,7 +6,7 @@ import BaserowFormulaVisitor from './BaserowFormulaVisitor.js'; const serializedATN = ["\u0003\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786", - "\u5964\u0003U`\u0004\u0002\t\u0002\u0004\u0003\t\u0003\u0004\u0004\t", + "\u5964\u0003Uc\u0004\u0002\t\u0002\u0004\u0003\t\u0003\u0004\u0004\t", "\u0004\u0004\u0005\t\u0005\u0004\u0006\t\u0006\u0004\u0007\t\u0007\u0003", "\u0002\u0003\u0002\u0003\u0002\u0003\u0003\u0003\u0003\u0003\u0003\u0003", "\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003", @@ -19,53 +19,55 @@ const serializedATN = ["\u0003\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786", "\u0005\u0003@\n\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003", "\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003", "\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003", - "\u0003\u0003\u0007\u0003S\n\u0003\f\u0003\u000e\u0003V\u000b\u0003\u0003", - "\u0004\u0003\u0004\u0003\u0005\u0003\u0005\u0003\u0006\u0003\u0006\u0003", - "\u0007\u0003\u0007\u0003\u0007\u0002\u0003\u0004\b\u0002\u0004\u0006", - "\b\n\f\u0002\u000b\u0003\u0002\u0006\u0007\u0004\u0002\u0010\u0010K", - "K\u0004\u0002??EE\u0004\u0002 BB\u0004\u0002+,67\u0004\u0002\'\'))", - "\u0003\u0002\u0003\u0005\u0003\u0002\u001b\u001c\u0003\u0002\u001d\u001e", - "\u0002l\u0002\u000e\u0003\u0002\u0002\u0002\u0004?\u0003\u0002\u0002", - "\u0002\u0006W\u0003\u0002\u0002\u0002\bY\u0003\u0002\u0002\u0002\n[", - "\u0003\u0002\u0002\u0002\f]\u0003\u0002\u0002\u0002\u000e\u000f\u0005", - "\u0004\u0003\u0002\u000f\u0010\u0007\u0002\u0002\u0003\u0010\u0003\u0003", - "\u0002\u0002\u0002\u0011\u0012\b\u0003\u0001\u0002\u0012@\u0007\u001b", - "\u0002\u0002\u0013@\u0007\u001c\u0002\u0002\u0014@\u0007\u0018\u0002", - "\u0002\u0015@\u0007\u0017\u0002\u0002\u0016@\t\u0002\u0002\u0002\u0017", - "\u0018\u0005\u0006\u0004\u0002\u0018\u0019\u0005\u0004\u0003\u000e\u0019", - "@\u0003\u0002\u0002\u0002\u001a\u001b\u0007\u0011\u0002\u0002\u001b", - "\u001c\u0005\u0004\u0003\u0002\u001c\u001d\u0007\u0012\u0002\u0002\u001d", - "@\u0003\u0002\u0002\u0002\u001e\u001f\u0007\b\u0002\u0002\u001f \u0007", - "\u0011\u0002\u0002 !\u0005\n\u0006\u0002!\"\u0007\u0012\u0002\u0002", - "\"@\u0003\u0002\u0002\u0002#$\u0007\t\u0002\u0002$%\u0007\u0011\u0002", - "\u0002%&\u0007\u0018\u0002\u0002&@\u0007\u0012\u0002\u0002\'(\u0007", - "\n\u0002\u0002()\u0007\u0011\u0002\u0002)*\u0005\n\u0006\u0002*,\u0007", - "\u000b\u0002\u0002+-\u0007\u0005\u0002\u0002,+\u0003\u0002\u0002\u0002", - ",-\u0003\u0002\u0002\u0002-.\u0003\u0002\u0002\u0002./\u0005\n\u0006", - "\u0002/0\u0007\u0012\u0002\u00020@\u0003\u0002\u0002\u000212\u0005\b", - "\u0005\u00022;\u0007\u0011\u0002\u000238\u0005\u0004\u0003\u000245\u0007", - "\u000b\u0002\u000257\u0005\u0004\u0003\u000264\u0003\u0002\u0002\u0002", - "7:\u0003\u0002\u0002\u000286\u0003\u0002\u0002\u000289\u0003\u0002\u0002", - "\u00029<\u0003\u0002\u0002\u0002:8\u0003\u0002\u0002\u0002;3\u0003\u0002", - "\u0002\u0002;<\u0003\u0002\u0002\u0002<=\u0003\u0002\u0002\u0002=>\u0007", - "\u0012\u0002\u0002>@\u0003\u0002\u0002\u0002?\u0011\u0003\u0002\u0002", - "\u0002?\u0013\u0003\u0002\u0002\u0002?\u0014\u0003\u0002\u0002\u0002", - "?\u0015\u0003\u0002\u0002\u0002?\u0016\u0003\u0002\u0002\u0002?\u0017", - "\u0003\u0002\u0002\u0002?\u001a\u0003\u0002\u0002\u0002?\u001e\u0003", - "\u0002\u0002\u0002?#\u0003\u0002\u0002\u0002?\'\u0003\u0002\u0002\u0002", - "?1\u0003\u0002\u0002\u0002@T\u0003\u0002\u0002\u0002AB\f\u000b\u0002", - "\u0002BC\t\u0003\u0002\u0002CS\u0005\u0004\u0003\fDE\f\n\u0002\u0002", - "EF\t\u0004\u0002\u0002FS\u0005\u0004\u0003\u000bGH\f\t\u0002\u0002H", - "I\t\u0005\u0002\u0002IS\u0005\u0004\u0003\nJK\f\b\u0002\u0002KL\t\u0006", - "\u0002\u0002LS\u0005\u0004\u0003\tMN\f\u0007\u0002\u0002NO\t\u0007\u0002", - "\u0002OS\u0005\u0004\u0003\bPQ\f\r\u0002\u0002QS\u0005\u0006\u0004\u0002", - "RA\u0003\u0002\u0002\u0002RD\u0003\u0002\u0002\u0002RG\u0003\u0002\u0002", - "\u0002RJ\u0003\u0002\u0002\u0002RM\u0003\u0002\u0002\u0002RP\u0003\u0002", - "\u0002\u0002SV\u0003\u0002\u0002\u0002TR\u0003\u0002\u0002\u0002TU\u0003", - "\u0002\u0002\u0002U\u0005\u0003\u0002\u0002\u0002VT\u0003\u0002\u0002", - "\u0002WX\t\b\u0002\u0002X\u0007\u0003\u0002\u0002\u0002YZ\u0005\f\u0007", - "\u0002Z\t\u0003\u0002\u0002\u0002[\\\t\t\u0002\u0002\\\u000b\u0003\u0002", - "\u0002\u0002]^\t\n\u0002\u0002^\r\u0003\u0002\u0002\u0002\b,8;?RT"].join(""); + "\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0003\u0007\u0003V\n\u0003", + "\f\u0003\u000e\u0003Y\u000b\u0003\u0003\u0004\u0003\u0004\u0003\u0005", + "\u0003\u0005\u0003\u0006\u0003\u0006\u0003\u0007\u0003\u0007\u0003\u0007", + "\u0002\u0003\u0004\b\u0002\u0004\u0006\b\n\f\u0002\n\u0003\u0002\u0006", + "\u0007\u0004\u0002\u0010\u0010KK\u0004\u0002??EE\u0004\u0002+,67\u0004", + "\u0002\'\'))\u0003\u0002\u0003\u0005\u0003\u0002\u001b\u001c\u0003\u0002", + "\u001d\u001e\u0002p\u0002\u000e\u0003\u0002\u0002\u0002\u0004?\u0003", + "\u0002\u0002\u0002\u0006Z\u0003\u0002\u0002\u0002\b\\\u0003\u0002\u0002", + "\u0002\n^\u0003\u0002\u0002\u0002\f`\u0003\u0002\u0002\u0002\u000e\u000f", + "\u0005\u0004\u0003\u0002\u000f\u0010\u0007\u0002\u0002\u0003\u0010\u0003", + "\u0003\u0002\u0002\u0002\u0011\u0012\b\u0003\u0001\u0002\u0012@\u0007", + "\u001b\u0002\u0002\u0013@\u0007\u001c\u0002\u0002\u0014@\u0007\u0018", + "\u0002\u0002\u0015@\u0007\u0017\u0002\u0002\u0016@\t\u0002\u0002\u0002", + "\u0017\u0018\u0005\u0006\u0004\u0002\u0018\u0019\u0005\u0004\u0003\u000f", + "\u0019@\u0003\u0002\u0002\u0002\u001a\u001b\u0007\u0011\u0002\u0002", + "\u001b\u001c\u0005\u0004\u0003\u0002\u001c\u001d\u0007\u0012\u0002\u0002", + "\u001d@\u0003\u0002\u0002\u0002\u001e\u001f\u0007\b\u0002\u0002\u001f", + " \u0007\u0011\u0002\u0002 !\u0005\n\u0006\u0002!\"\u0007\u0012\u0002", + "\u0002\"@\u0003\u0002\u0002\u0002#$\u0007\t\u0002\u0002$%\u0007\u0011", + "\u0002\u0002%&\u0007\u0018\u0002\u0002&@\u0007\u0012\u0002\u0002\'(", + "\u0007\n\u0002\u0002()\u0007\u0011\u0002\u0002)*\u0005\n\u0006\u0002", + "*,\u0007\u000b\u0002\u0002+-\u0007\u0005\u0002\u0002,+\u0003\u0002\u0002", + "\u0002,-\u0003\u0002\u0002\u0002-.\u0003\u0002\u0002\u0002./\u0005\n", + "\u0006\u0002/0\u0007\u0012\u0002\u00020@\u0003\u0002\u0002\u000212\u0005", + "\b\u0005\u00022;\u0007\u0011\u0002\u000238\u0005\u0004\u0003\u00024", + "5\u0007\u000b\u0002\u000257\u0005\u0004\u0003\u000264\u0003\u0002\u0002", + "\u00027:\u0003\u0002\u0002\u000286\u0003\u0002\u0002\u000289\u0003\u0002", + "\u0002\u00029<\u0003\u0002\u0002\u0002:8\u0003\u0002\u0002\u0002;3\u0003", + "\u0002\u0002\u0002;<\u0003\u0002\u0002\u0002<=\u0003\u0002\u0002\u0002", + "=>\u0007\u0012\u0002\u0002>@\u0003\u0002\u0002\u0002?\u0011\u0003\u0002", + "\u0002\u0002?\u0013\u0003\u0002\u0002\u0002?\u0014\u0003\u0002\u0002", + "\u0002?\u0015\u0003\u0002\u0002\u0002?\u0016\u0003\u0002\u0002\u0002", + "?\u0017\u0003\u0002\u0002\u0002?\u001a\u0003\u0002\u0002\u0002?\u001e", + "\u0003\u0002\u0002\u0002?#\u0003\u0002\u0002\u0002?\'\u0003\u0002\u0002", + "\u0002?1\u0003\u0002\u0002\u0002@W\u0003\u0002\u0002\u0002AB\f\f\u0002", + "\u0002BC\t\u0003\u0002\u0002CV\u0005\u0004\u0003\rDE\f\u000b\u0002\u0002", + "EF\t\u0004\u0002\u0002FV\u0005\u0004\u0003\fGH\f\n\u0002\u0002HI\t\u0005", + "\u0002\u0002IV\u0005\u0004\u0003\u000bJK\f\t\u0002\u0002KL\t\u0006\u0002", + "\u0002LV\u0005\u0004\u0003\nMN\f\b\u0002\u0002NO\u0007 \u0002\u0002", + "OV\u0005\u0004\u0003\tPQ\f\u0007\u0002\u0002QR\u0007B\u0002\u0002RV", + "\u0005\u0004\u0003\bST\f\u000e\u0002\u0002TV\u0005\u0006\u0004\u0002", + "UA\u0003\u0002\u0002\u0002UD\u0003\u0002\u0002\u0002UG\u0003\u0002\u0002", + "\u0002UJ\u0003\u0002\u0002\u0002UM\u0003\u0002\u0002\u0002UP\u0003\u0002", + "\u0002\u0002US\u0003\u0002\u0002\u0002VY\u0003\u0002\u0002\u0002WU\u0003", + "\u0002\u0002\u0002WX\u0003\u0002\u0002\u0002X\u0005\u0003\u0002\u0002", + "\u0002YW\u0003\u0002\u0002\u0002Z[\t\u0007\u0002\u0002[\u0007\u0003", + "\u0002\u0002\u0002\\]\u0005\f\u0007\u0002]\t\u0003\u0002\u0002\u0002", + "^_\t\b\u0002\u0002_\u000b\u0003\u0002\u0002\u0002`a\t\t\u0002\u0002", + "a\r\u0003\u0002\u0002\u0002\b,8;?UW"].join(""); const atn = new antlr4.atn.ATNDeserializer().deserialize(serializedATN); @@ -138,17 +140,19 @@ export default class BaserowFormula extends antlr4.Parser { expr_sempred(localctx, predIndex) { switch(predIndex) { case 0: - return this.precpred(this._ctx, 9); + return this.precpred(this._ctx, 10); case 1: - return this.precpred(this._ctx, 8); + return this.precpred(this._ctx, 9); case 2: - return this.precpred(this._ctx, 7); + return this.precpred(this._ctx, 8); case 3: - return this.precpred(this._ctx, 6); + return this.precpred(this._ctx, 7); case 4: - return this.precpred(this._ctx, 5); + return this.precpred(this._ctx, 6); case 5: - return this.precpred(this._ctx, 11); + return this.precpred(this._ctx, 5); + case 6: + return this.precpred(this._ctx, 12); default: throw "No predicate with index:" + predIndex; } @@ -250,7 +254,7 @@ export default class BaserowFormula extends antlr4.Parser { this.state = 21; this.ws_or_comment(); this.state = 22; - this.expr(12); + this.expr(13); break; case BaserowFormula.OPEN_PAREN: localctx = new BracketsContext(this, localctx); @@ -350,7 +354,7 @@ export default class BaserowFormula extends antlr4.Parser { throw new antlr4.error.NoViableAltException(this); } this._ctx.stop = this._input.LT(-1); - this.state = 82; + this.state = 85; this._errHandler.sync(this); let _alt = this._interp.adaptivePredict(this._input,5,this._ctx) while(_alt!=2 && _alt!=antlr4.atn.ATN.INVALID_ALT_NUMBER) { @@ -359,7 +363,7 @@ export default class BaserowFormula extends antlr4.Parser { this.triggerExitRuleEvent(); } _prevctx = localctx; - this.state = 80; + this.state = 83; this._errHandler.sync(this); var la_ = this._interp.adaptivePredict(this._input,4,this._ctx); switch(la_) { @@ -367,8 +371,8 @@ export default class BaserowFormula extends antlr4.Parser { localctx = new BinaryOpContext(this, new ExprContext(this, _parentctx, _parentState)); this.pushNewRecursionContext(localctx, _startState, BaserowFormula.RULE_expr); this.state = 63; - if (!( this.precpred(this._ctx, 9))) { - throw new antlr4.error.FailedPredicateException(this, "this.precpred(this._ctx, 9)"); + if (!( this.precpred(this._ctx, 10))) { + throw new antlr4.error.FailedPredicateException(this, "this.precpred(this._ctx, 10)"); } this.state = 64; localctx.op = this._input.LT(1); @@ -381,15 +385,15 @@ export default class BaserowFormula extends antlr4.Parser { this.consume(); } this.state = 65; - this.expr(10); + this.expr(11); break; case 2: localctx = new BinaryOpContext(this, new ExprContext(this, _parentctx, _parentState)); this.pushNewRecursionContext(localctx, _startState, BaserowFormula.RULE_expr); this.state = 66; - if (!( this.precpred(this._ctx, 8))) { - throw new antlr4.error.FailedPredicateException(this, "this.precpred(this._ctx, 8)"); + if (!( this.precpred(this._ctx, 9))) { + throw new antlr4.error.FailedPredicateException(this, "this.precpred(this._ctx, 9)"); } this.state = 67; localctx.op = this._input.LT(1); @@ -402,20 +406,20 @@ export default class BaserowFormula extends antlr4.Parser { this.consume(); } this.state = 68; - this.expr(9); + this.expr(10); break; case 3: localctx = new BinaryOpContext(this, new ExprContext(this, _parentctx, _parentState)); this.pushNewRecursionContext(localctx, _startState, BaserowFormula.RULE_expr); this.state = 69; - if (!( this.precpred(this._ctx, 7))) { - throw new antlr4.error.FailedPredicateException(this, "this.precpred(this._ctx, 7)"); + if (!( this.precpred(this._ctx, 8))) { + throw new antlr4.error.FailedPredicateException(this, "this.precpred(this._ctx, 8)"); } this.state = 70; localctx.op = this._input.LT(1); _la = this._input.LA(1); - if(!(_la===BaserowFormula.AMP_AMP || _la===BaserowFormula.PIPE_PIPE)) { + if(!(((((_la - 41)) & ~0x1f) == 0 && ((1 << (_la - 41)) & ((1 << (BaserowFormula.GT - 41)) | (1 << (BaserowFormula.GTE - 41)) | (1 << (BaserowFormula.LT - 41)) | (1 << (BaserowFormula.LTE - 41)))) !== 0))) { localctx.op = this._errHandler.recoverInline(this); } else { @@ -423,20 +427,20 @@ export default class BaserowFormula extends antlr4.Parser { this.consume(); } this.state = 71; - this.expr(8); + this.expr(9); break; case 4: localctx = new BinaryOpContext(this, new ExprContext(this, _parentctx, _parentState)); this.pushNewRecursionContext(localctx, _startState, BaserowFormula.RULE_expr); this.state = 72; - if (!( this.precpred(this._ctx, 6))) { - throw new antlr4.error.FailedPredicateException(this, "this.precpred(this._ctx, 6)"); + if (!( this.precpred(this._ctx, 7))) { + throw new antlr4.error.FailedPredicateException(this, "this.precpred(this._ctx, 7)"); } this.state = 73; localctx.op = this._input.LT(1); _la = this._input.LA(1); - if(!(((((_la - 41)) & ~0x1f) == 0 && ((1 << (_la - 41)) & ((1 << (BaserowFormula.GT - 41)) | (1 << (BaserowFormula.GTE - 41)) | (1 << (BaserowFormula.LT - 41)) | (1 << (BaserowFormula.LTE - 41)))) !== 0))) { + if(!(_la===BaserowFormula.BANG_EQUAL || _la===BaserowFormula.EQUAL)) { localctx.op = this._errHandler.recoverInline(this); } else { @@ -444,44 +448,49 @@ export default class BaserowFormula extends antlr4.Parser { this.consume(); } this.state = 74; - this.expr(7); + this.expr(8); break; case 5: localctx = new BinaryOpContext(this, new ExprContext(this, _parentctx, _parentState)); this.pushNewRecursionContext(localctx, _startState, BaserowFormula.RULE_expr); this.state = 75; - if (!( this.precpred(this._ctx, 5))) { - throw new antlr4.error.FailedPredicateException(this, "this.precpred(this._ctx, 5)"); + if (!( this.precpred(this._ctx, 6))) { + throw new antlr4.error.FailedPredicateException(this, "this.precpred(this._ctx, 6)"); } this.state = 76; - localctx.op = this._input.LT(1); - _la = this._input.LA(1); - if(!(_la===BaserowFormula.BANG_EQUAL || _la===BaserowFormula.EQUAL)) { - localctx.op = this._errHandler.recoverInline(this); - } - else { - this._errHandler.reportMatch(this); - this.consume(); - } + localctx.op = this.match(BaserowFormula.AMP_AMP); this.state = 77; - this.expr(6); + this.expr(7); break; case 6: - localctx = new RightWhitespaceOrCommentsContext(this, new ExprContext(this, _parentctx, _parentState)); + localctx = new BinaryOpContext(this, new ExprContext(this, _parentctx, _parentState)); this.pushNewRecursionContext(localctx, _startState, BaserowFormula.RULE_expr); this.state = 78; - if (!( this.precpred(this._ctx, 11))) { - throw new antlr4.error.FailedPredicateException(this, "this.precpred(this._ctx, 11)"); + if (!( this.precpred(this._ctx, 5))) { + throw new antlr4.error.FailedPredicateException(this, "this.precpred(this._ctx, 5)"); } this.state = 79; + localctx.op = this.match(BaserowFormula.PIPE_PIPE); + this.state = 80; + this.expr(6); + break; + + case 7: + localctx = new RightWhitespaceOrCommentsContext(this, new ExprContext(this, _parentctx, _parentState)); + this.pushNewRecursionContext(localctx, _startState, BaserowFormula.RULE_expr); + this.state = 81; + if (!( this.precpred(this._ctx, 12))) { + throw new antlr4.error.FailedPredicateException(this, "this.precpred(this._ctx, 12)"); + } + this.state = 82; this.ws_or_comment(); break; } } - this.state = 84; + this.state = 87; this._errHandler.sync(this); _alt = this._interp.adaptivePredict(this._input,5,this._ctx); } @@ -508,7 +517,7 @@ export default class BaserowFormula extends antlr4.Parser { var _la = 0; // Token type try { this.enterOuterAlt(localctx, 1); - this.state = 85; + this.state = 88; _la = this._input.LA(1); if(!((((_la) & ~0x1f) == 0 && ((1 << _la) & ((1 << BaserowFormula.BLOCK_COMMENT) | (1 << BaserowFormula.LINE_COMMENT) | (1 << BaserowFormula.WHITESPACE))) !== 0))) { this._errHandler.recoverInline(this); @@ -538,7 +547,7 @@ export default class BaserowFormula extends antlr4.Parser { this.enterRule(localctx, 6, BaserowFormula.RULE_func_name); try { this.enterOuterAlt(localctx, 1); - this.state = 87; + this.state = 90; this.identifier(); } catch (re) { if(re instanceof antlr4.error.RecognitionException) { @@ -562,7 +571,7 @@ export default class BaserowFormula extends antlr4.Parser { var _la = 0; // Token type try { this.enterOuterAlt(localctx, 1); - this.state = 89; + this.state = 92; _la = this._input.LA(1); if(!(_la===BaserowFormula.SINGLEQ_STRING_LITERAL || _la===BaserowFormula.DOUBLEQ_STRING_LITERAL)) { this._errHandler.recoverInline(this); @@ -593,7 +602,7 @@ export default class BaserowFormula extends antlr4.Parser { var _la = 0; // Token type try { this.enterOuterAlt(localctx, 1); - this.state = 91; + this.state = 94; _la = this._input.LA(1); if(!(_la===BaserowFormula.IDENTIFIER || _la===BaserowFormula.IDENTIFIER_UNICODE)) { this._errHandler.recoverInline(this); @@ -1318,14 +1327,6 @@ class BinaryOpContext extends ExprContext { return this.getToken(BaserowFormula.MINUS, 0); }; - AMP_AMP() { - return this.getToken(BaserowFormula.AMP_AMP, 0); - }; - - PIPE_PIPE() { - return this.getToken(BaserowFormula.PIPE_PIPE, 0); - }; - GT() { return this.getToken(BaserowFormula.GT, 0); }; @@ -1350,6 +1351,14 @@ class BinaryOpContext extends ExprContext { return this.getToken(BaserowFormula.BANG_EQUAL, 0); }; + AMP_AMP() { + return this.getToken(BaserowFormula.AMP_AMP, 0); + }; + + PIPE_PIPE() { + return this.getToken(BaserowFormula.PIPE_PIPE, 0); + }; + enterRule(listener) { if(listener instanceof BaserowFormulaListener ) { listener.enterBinaryOp(this);