|
10 | 10 | import static org.opensearch.sql.ast.dsl.AstDSL.agg; |
11 | 11 | import static org.opensearch.sql.ast.dsl.AstDSL.aggregate; |
12 | 12 | import static org.opensearch.sql.ast.dsl.AstDSL.alias; |
| 13 | +import static org.opensearch.sql.ast.dsl.AstDSL.allFields; |
13 | 14 | import static org.opensearch.sql.ast.dsl.AstDSL.and; |
14 | 15 | import static org.opensearch.sql.ast.dsl.AstDSL.argument; |
15 | 16 | import static org.opensearch.sql.ast.dsl.AstDSL.booleanLiteral; |
|
42 | 43 | import static org.opensearch.sql.ast.dsl.AstDSL.relation; |
43 | 44 | import static org.opensearch.sql.ast.dsl.AstDSL.search; |
44 | 45 | import static org.opensearch.sql.ast.dsl.AstDSL.sort; |
| 46 | +import static org.opensearch.sql.ast.dsl.AstDSL.span; |
45 | 47 | import static org.opensearch.sql.ast.dsl.AstDSL.stringLiteral; |
46 | 48 | import static org.opensearch.sql.ast.dsl.AstDSL.unresolvedArg; |
47 | 49 | import static org.opensearch.sql.ast.dsl.AstDSL.when; |
|
58 | 60 | import org.opensearch.sql.ast.expression.AllFields; |
59 | 61 | import org.opensearch.sql.ast.expression.DataType; |
60 | 62 | import org.opensearch.sql.ast.expression.RelevanceFieldList; |
| 63 | +import org.opensearch.sql.ast.expression.SpanUnit; |
| 64 | +import org.opensearch.sql.ast.tree.Timechart; |
| 65 | +import org.opensearch.sql.calcite.plan.OpenSearchConstants; |
61 | 66 | import org.opensearch.sql.common.antlr.SyntaxCheckException; |
62 | 67 |
|
63 | 68 | public class AstExpressionBuilderTest extends AstBuilderTest { |
@@ -1360,4 +1365,222 @@ public void testMedianAggFuncExpr() { |
1360 | 1365 | emptyList(), |
1361 | 1366 | defaultStatsArgs())); |
1362 | 1367 | } |
| 1368 | + |
| 1369 | + @Test |
| 1370 | + public void testTimechartSpanParameter() { |
| 1371 | + assertEqual( |
| 1372 | + "source=t | timechart span=30m count()", |
| 1373 | + Timechart.builder() |
| 1374 | + .child(relation("t")) |
| 1375 | + .binExpression( |
| 1376 | + span( |
| 1377 | + field(OpenSearchConstants.IMPLICIT_FIELD_TIMESTAMP), |
| 1378 | + intLiteral(30), |
| 1379 | + SpanUnit.m)) |
| 1380 | + .aggregateFunction(aggregate("count", allFields())) |
| 1381 | + .limit(10) |
| 1382 | + .useOther(true) |
| 1383 | + .build()); |
| 1384 | + } |
| 1385 | + |
| 1386 | + @Test |
| 1387 | + public void testTimechartLimitParameter() { |
| 1388 | + assertEqual( |
| 1389 | + "source=t | timechart limit=100 count()", |
| 1390 | + Timechart.builder() |
| 1391 | + .child(relation("t")) |
| 1392 | + .binExpression( |
| 1393 | + span( |
| 1394 | + field(OpenSearchConstants.IMPLICIT_FIELD_TIMESTAMP), intLiteral(1), SpanUnit.m)) |
| 1395 | + .aggregateFunction(aggregate("count", allFields())) |
| 1396 | + .limit(100) |
| 1397 | + .useOther(true) |
| 1398 | + .build()); |
| 1399 | + } |
| 1400 | + |
| 1401 | + @Test |
| 1402 | + public void testTimechartNegativeLimitParameter() { |
| 1403 | + assertThrows( |
| 1404 | + IllegalArgumentException.class, |
| 1405 | + () -> assertEqual("source=t | timechart limit=-1 count()", (Node) null)); |
| 1406 | + } |
| 1407 | + |
| 1408 | + @Test |
| 1409 | + public void testTimechartUseOtherWithBooleanLiteral() { |
| 1410 | + assertEqual( |
| 1411 | + "source=t | timechart useother=true count()", |
| 1412 | + Timechart.builder() |
| 1413 | + .child(relation("t")) |
| 1414 | + .binExpression( |
| 1415 | + span( |
| 1416 | + field(OpenSearchConstants.IMPLICIT_FIELD_TIMESTAMP), intLiteral(1), SpanUnit.m)) |
| 1417 | + .aggregateFunction(aggregate("count", allFields())) |
| 1418 | + .limit(10) |
| 1419 | + .useOther(true) |
| 1420 | + .build()); |
| 1421 | + |
| 1422 | + assertEqual( |
| 1423 | + "source=t | timechart useother=false count()", |
| 1424 | + Timechart.builder() |
| 1425 | + .child(relation("t")) |
| 1426 | + .binExpression( |
| 1427 | + span( |
| 1428 | + field(OpenSearchConstants.IMPLICIT_FIELD_TIMESTAMP), intLiteral(1), SpanUnit.m)) |
| 1429 | + .aggregateFunction(aggregate("count", allFields())) |
| 1430 | + .limit(10) |
| 1431 | + .useOther(false) |
| 1432 | + .build()); |
| 1433 | + } |
| 1434 | + |
| 1435 | + @Test |
| 1436 | + public void testTimechartUseOtherWithIdentifier() { |
| 1437 | + assertEqual( |
| 1438 | + "source=t | timechart useother=t count()", |
| 1439 | + Timechart.builder() |
| 1440 | + .child(relation("t")) |
| 1441 | + .binExpression( |
| 1442 | + span( |
| 1443 | + field(OpenSearchConstants.IMPLICIT_FIELD_TIMESTAMP), intLiteral(1), SpanUnit.m)) |
| 1444 | + .aggregateFunction(aggregate("count", allFields())) |
| 1445 | + .limit(10) |
| 1446 | + .useOther(true) |
| 1447 | + .build()); |
| 1448 | + |
| 1449 | + assertEqual( |
| 1450 | + "source=t | timechart useother=f count()", |
| 1451 | + Timechart.builder() |
| 1452 | + .child(relation("t")) |
| 1453 | + .binExpression( |
| 1454 | + span( |
| 1455 | + field(OpenSearchConstants.IMPLICIT_FIELD_TIMESTAMP), intLiteral(1), SpanUnit.m)) |
| 1456 | + .aggregateFunction(aggregate("count", allFields())) |
| 1457 | + .limit(10) |
| 1458 | + .useOther(false) |
| 1459 | + .build()); |
| 1460 | + |
| 1461 | + assertEqual( |
| 1462 | + "source=t | timechart useother=TRUE count()", |
| 1463 | + Timechart.builder() |
| 1464 | + .child(relation("t")) |
| 1465 | + .binExpression( |
| 1466 | + span( |
| 1467 | + field(OpenSearchConstants.IMPLICIT_FIELD_TIMESTAMP), intLiteral(1), SpanUnit.m)) |
| 1468 | + .aggregateFunction(aggregate("count", allFields())) |
| 1469 | + .limit(10) |
| 1470 | + .useOther(true) |
| 1471 | + .build()); |
| 1472 | + |
| 1473 | + assertEqual( |
| 1474 | + "source=t | timechart useother=FALSE count()", |
| 1475 | + Timechart.builder() |
| 1476 | + .child(relation("t")) |
| 1477 | + .binExpression( |
| 1478 | + span( |
| 1479 | + field(OpenSearchConstants.IMPLICIT_FIELD_TIMESTAMP), intLiteral(1), SpanUnit.m)) |
| 1480 | + .aggregateFunction(aggregate("count", allFields())) |
| 1481 | + .limit(10) |
| 1482 | + .useOther(false) |
| 1483 | + .build()); |
| 1484 | + } |
| 1485 | + |
| 1486 | + @Test |
| 1487 | + public void testTimechartInvalidUseOtherValue() { |
| 1488 | + assertThrows( |
| 1489 | + IllegalArgumentException.class, |
| 1490 | + () -> assertEqual("source=t | timechart useother=invalid count()", (Node) null)); |
| 1491 | + } |
| 1492 | + |
| 1493 | + @Test |
| 1494 | + public void testTimechartInvalidParameter() { |
| 1495 | + assertThrows( |
| 1496 | + SyntaxCheckException.class, |
| 1497 | + () -> assertEqual("source=t | timechart invalidparam=value count()", (Node) null)); |
| 1498 | + } |
| 1499 | + |
| 1500 | + @Test |
| 1501 | + public void testVisitSpanClause() { |
| 1502 | + // Test span clause with explicit field |
| 1503 | + assertEqual( |
| 1504 | + "source=t | stats count() by span(timestamp, 1h)", |
| 1505 | + agg( |
| 1506 | + relation("t"), |
| 1507 | + exprList(alias("count()", aggregate("count", AllFields.of()))), |
| 1508 | + emptyList(), |
| 1509 | + emptyList(), |
| 1510 | + alias("span(timestamp,1h)", span(field("timestamp"), intLiteral(1), SpanUnit.H)), |
| 1511 | + defaultStatsArgs())); |
| 1512 | + |
| 1513 | + // Test span clause with different time unit |
| 1514 | + assertEqual( |
| 1515 | + "source=t | stats count() by span(timestamp, 5d)", |
| 1516 | + agg( |
| 1517 | + relation("t"), |
| 1518 | + exprList(alias("count()", aggregate("count", AllFields.of()))), |
| 1519 | + emptyList(), |
| 1520 | + emptyList(), |
| 1521 | + alias("span(timestamp,5d)", span(field("timestamp"), intLiteral(5), SpanUnit.D)), |
| 1522 | + defaultStatsArgs())); |
| 1523 | + |
| 1524 | + // Test span clause with implicit @timestamp field |
| 1525 | + assertEqual( |
| 1526 | + "source=t | stats count() by span(1m)", |
| 1527 | + agg( |
| 1528 | + relation("t"), |
| 1529 | + exprList(alias("count()", aggregate("count", AllFields.of()))), |
| 1530 | + emptyList(), |
| 1531 | + emptyList(), |
| 1532 | + alias( |
| 1533 | + "span(1m)", |
| 1534 | + span( |
| 1535 | + field(OpenSearchConstants.IMPLICIT_FIELD_TIMESTAMP), |
| 1536 | + intLiteral(1), |
| 1537 | + SpanUnit.m)), |
| 1538 | + defaultStatsArgs())); |
| 1539 | + } |
| 1540 | + |
| 1541 | + @Test |
| 1542 | + public void testVisitSpanLiteral() { |
| 1543 | + // Test span literal with integer value and hour unit |
| 1544 | + assertEqual( |
| 1545 | + "source=t | timechart span=1h count()", |
| 1546 | + Timechart.builder() |
| 1547 | + .child(relation("t")) |
| 1548 | + .binExpression( |
| 1549 | + span( |
| 1550 | + field(OpenSearchConstants.IMPLICIT_FIELD_TIMESTAMP), intLiteral(1), SpanUnit.H)) |
| 1551 | + .aggregateFunction(aggregate("count", allFields())) |
| 1552 | + .limit(10) |
| 1553 | + .useOther(true) |
| 1554 | + .build()); |
| 1555 | + |
| 1556 | + // Test span literal with decimal value and minute unit |
| 1557 | + assertEqual( |
| 1558 | + "source=t | timechart span=2.5m count()", |
| 1559 | + Timechart.builder() |
| 1560 | + .child(relation("t")) |
| 1561 | + .binExpression( |
| 1562 | + span( |
| 1563 | + field(OpenSearchConstants.IMPLICIT_FIELD_TIMESTAMP), |
| 1564 | + decimalLiteral(2.5), |
| 1565 | + SpanUnit.m)) |
| 1566 | + .aggregateFunction(aggregate("count", allFields())) |
| 1567 | + .limit(10) |
| 1568 | + .useOther(true) |
| 1569 | + .build()); |
| 1570 | + |
| 1571 | + // Test span literal without unit (should use NONE unit) |
| 1572 | + assertEqual( |
| 1573 | + "source=t | timechart span=10 count()", |
| 1574 | + Timechart.builder() |
| 1575 | + .child(relation("t")) |
| 1576 | + .binExpression( |
| 1577 | + span( |
| 1578 | + field(OpenSearchConstants.IMPLICIT_FIELD_TIMESTAMP), |
| 1579 | + intLiteral(10), |
| 1580 | + SpanUnit.NONE)) |
| 1581 | + .aggregateFunction(aggregate("count", allFields())) |
| 1582 | + .limit(10) |
| 1583 | + .useOther(true) |
| 1584 | + .build()); |
| 1585 | + } |
1363 | 1586 | } |
0 commit comments