@ -2,6 +2,7 @@ package engine
import (
import (
"testing"
"testing"
"time"
"github.com/seaweedfs/seaweedfs/weed/pb/schema_pb"
"github.com/seaweedfs/seaweedfs/weed/pb/schema_pb"
)
)
@ -528,3 +529,241 @@ func TestMathematicalFunctions(t *testing.T) {
}
}
} )
} )
}
}
func TestDateTimeFunctions ( t * testing . T ) {
engine := NewTestSQLEngine ( )
t . Run ( "CURRENT_DATE function tests" , func ( t * testing . T ) {
result , err := engine . CurrentDate ( )
if err != nil {
t . Errorf ( "CurrentDate failed: %v" , err )
}
if result == nil {
t . Errorf ( "CurrentDate returned nil result" )
return
}
stringVal , ok := result . Kind . ( * schema_pb . Value_StringValue )
if ! ok {
t . Errorf ( "CurrentDate should return string value, got %T" , result . Kind )
return
}
// Check format (YYYY-MM-DD)
today := time . Now ( ) . Format ( "2006-01-02" )
if stringVal . StringValue != today {
t . Errorf ( "Expected current date %s, got %s" , today , stringVal . StringValue )
}
} )
t . Run ( "CURRENT_TIMESTAMP function tests" , func ( t * testing . T ) {
before := time . Now ( )
result , err := engine . CurrentTimestamp ( )
after := time . Now ( )
if err != nil {
t . Errorf ( "CurrentTimestamp failed: %v" , err )
}
if result == nil {
t . Errorf ( "CurrentTimestamp returned nil result" )
return
}
timestampVal , ok := result . Kind . ( * schema_pb . Value_TimestampValue )
if ! ok {
t . Errorf ( "CurrentTimestamp should return timestamp value, got %T" , result . Kind )
return
}
timestamp := time . UnixMicro ( timestampVal . TimestampValue . TimestampMicros )
// Check that timestamp is within reasonable range
if timestamp . Before ( before ) || timestamp . After ( after ) {
t . Errorf ( "Timestamp %v should be between %v and %v" , timestamp , before , after )
}
} )
t . Run ( "NOW function tests" , func ( t * testing . T ) {
result , err := engine . Now ( )
if err != nil {
t . Errorf ( "Now failed: %v" , err )
}
if result == nil {
t . Errorf ( "Now returned nil result" )
return
}
// Should return same type as CurrentTimestamp
_ , ok := result . Kind . ( * schema_pb . Value_TimestampValue )
if ! ok {
t . Errorf ( "Now should return timestamp value, got %T" , result . Kind )
}
} )
t . Run ( "CURRENT_TIME function tests" , func ( t * testing . T ) {
result , err := engine . CurrentTime ( )
if err != nil {
t . Errorf ( "CurrentTime failed: %v" , err )
}
if result == nil {
t . Errorf ( "CurrentTime returned nil result" )
return
}
stringVal , ok := result . Kind . ( * schema_pb . Value_StringValue )
if ! ok {
t . Errorf ( "CurrentTime should return string value, got %T" , result . Kind )
return
}
// Check format (HH:MM:SS)
if len ( stringVal . StringValue ) != 8 || stringVal . StringValue [ 2 ] != ':' || stringVal . StringValue [ 5 ] != ':' {
t . Errorf ( "CurrentTime should return HH:MM:SS format, got %s" , stringVal . StringValue )
}
} )
}
func TestExtractFunction ( t * testing . T ) {
engine := NewTestSQLEngine ( )
// Create a test timestamp: 2023-06-15 14:30:45
// Use local time to avoid timezone conversion issues
testTime := time . Date ( 2023 , 6 , 15 , 14 , 30 , 45 , 0 , time . Local )
testTimestamp := & schema_pb . Value {
Kind : & schema_pb . Value_TimestampValue {
TimestampValue : & schema_pb . TimestampValue {
TimestampMicros : testTime . UnixMicro ( ) ,
} ,
} ,
}
tests := [ ] struct {
name string
part DatePart
value * schema_pb . Value
expected int64
expectErr bool
} {
{
name : "Extract YEAR" ,
part : PartYear ,
value : testTimestamp ,
expected : 2023 ,
expectErr : false ,
} ,
{
name : "Extract MONTH" ,
part : PartMonth ,
value : testTimestamp ,
expected : 6 ,
expectErr : false ,
} ,
{
name : "Extract DAY" ,
part : PartDay ,
value : testTimestamp ,
expected : 15 ,
expectErr : false ,
} ,
{
name : "Extract HOUR" ,
part : PartHour ,
value : testTimestamp ,
expected : 14 ,
expectErr : false ,
} ,
{
name : "Extract MINUTE" ,
part : PartMinute ,
value : testTimestamp ,
expected : 30 ,
expectErr : false ,
} ,
{
name : "Extract SECOND" ,
part : PartSecond ,
value : testTimestamp ,
expected : 45 ,
expectErr : false ,
} ,
{
name : "Extract QUARTER from June" ,
part : PartQuarter ,
value : testTimestamp ,
expected : 2 , // June is in Q2
expectErr : false ,
} ,
{
name : "Extract from string date" ,
part : PartYear ,
value : & schema_pb . Value { Kind : & schema_pb . Value_StringValue { StringValue : "2023-06-15" } } ,
expected : 2023 ,
expectErr : false ,
} ,
{
name : "Extract from Unix timestamp" ,
part : PartYear ,
value : & schema_pb . Value { Kind : & schema_pb . Value_Int64Value { Int64Value : testTime . Unix ( ) } } ,
expected : 2023 ,
expectErr : false ,
} ,
{
name : "Extract from null value" ,
part : PartYear ,
value : nil ,
expected : 0 ,
expectErr : true ,
} ,
{
name : "Extract invalid part" ,
part : DatePart ( "INVALID" ) ,
value : testTimestamp ,
expected : 0 ,
expectErr : true ,
} ,
{
name : "Extract from invalid string" ,
part : PartYear ,
value : & schema_pb . Value { Kind : & schema_pb . Value_StringValue { StringValue : "invalid-date" } } ,
expected : 0 ,
expectErr : true ,
} ,
}
for _ , tt := range tests {
t . Run ( tt . name , func ( t * testing . T ) {
result , err := engine . Extract ( tt . part , tt . value )
if tt . expectErr {
if err == nil {
t . Errorf ( "Expected error but got none" )
}
return
}
if err != nil {
t . Errorf ( "Unexpected error: %v" , err )
return
}
if result == nil {
t . Errorf ( "Extract returned nil result" )
return
}
intVal , ok := result . Kind . ( * schema_pb . Value_Int64Value )
if ! ok {
t . Errorf ( "Extract should return int64 value, got %T" , result . Kind )
return
}
if intVal . Int64Value != tt . expected {
t . Errorf ( "Expected %d, got %d" , tt . expected , intVal . Int64Value )
}
} )
}
}