Skip to content

Instantly share code, notes, and snippets.

@kylebrandt
Created April 1, 2025 18:33
Show Gist options
  • Save kylebrandt/e96c08ce08db9188978d72bd30fa38c7 to your computer and use it in GitHub Desktop.
Save kylebrandt/e96c08ce08db9188978d72bd30fa38c7 to your computer and use it in GitHub Desktop.

Revisions

  1. kylebrandt created this gist Apr 1, 2025.
    107 changes: 107 additions & 0 deletions time_funcs.go
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,107 @@
    package sql

    import (
    "context"
    "time"

    mysql "github.com/dolthub/go-mysql-server/sql"
    "github.com/dolthub/go-mysql-server/sql/types"
    )

    type timeRangeKey struct{}

    type TimeRange struct {
    From time.Time
    To time.Time
    }

    func WithTimeRange(ctx context.Context, from, to time.Time) context.Context {
    return context.WithValue(ctx, timeRangeKey{}, TimeRange{From: from, To: to})
    }

    func GetTimeRange(ctx context.Context) (TimeRange, bool) {
    tr, ok := ctx.Value(timeRangeKey{}).(TimeRange)
    return tr, ok

    }

    //
    // Expressions for time_from() and time_to()
    //

    type TimeFromExpr struct{}

    func (e *TimeFromExpr) Resolved() bool { return true }
    func (e *TimeFromExpr) IsNullable() bool { return false }
    func (e *TimeFromExpr) Children() []mysql.Expression { return nil }
    func (e *TimeFromExpr) WithChildren(...mysql.Expression) (mysql.Expression, error) {
    return e, nil
    }
    func (e *TimeFromExpr) String() string { return "time_from()" }
    func (e *TimeFromExpr) Type() mysql.Type { return types.Timestamp }
    func (e *TimeFromExpr) Eval(ctx *mysql.Context, _ mysql.Row) (interface{}, error) {
    if tr, ok := GetTimeRange(ctx.Context); ok {
    return tr.From, nil
    }
    return nil, nil
    }

    type TimeToExpr struct{}

    func (e *TimeToExpr) Resolved() bool { return true }
    func (e *TimeToExpr) IsNullable() bool { return false }
    func (e *TimeToExpr) Children() []mysql.Expression { return nil }
    func (e *TimeToExpr) WithChildren(...mysql.Expression) (mysql.Expression, error) {
    return e, nil
    }
    func (e *TimeToExpr) String() string { return "time_to()" }
    func (e *TimeToExpr) Type() mysql.Type { return types.Timestamp }
    func (e *TimeToExpr) Eval(ctx *mysql.Context, _ mysql.Row) (interface{}, error) {
    if tr, ok := GetTimeRange(ctx.Context); ok {
    return tr.To, nil
    }
    return nil, nil
    }

    //
    // sql.Function implementations
    //

    type timeFromFunction struct{}

    func (*timeFromFunction) isFunction() {}

    func (f *timeFromFunction) FunctionName() string {
    return "time_from"
    }
    func (f *timeFromFunction) NewInstance(args []mysql.Expression) (mysql.Expression, error) {
    return &TimeFromExpr{}, nil
    }

    type timeToFunction struct{}

    func (*timeToFunction) isFunction() {}

    func (f *timeToFunction) FunctionName() string {
    return "time_to"
    }
    func (f *timeToFunction) NewInstance(args []mysql.Expression) (mysql.Expression, error) {
    return &TimeToExpr{}, nil
    }

    //
    // FunctionProvider to register both functions
    //

    type TimeFuncProvider struct{}

    func (p *TimeFuncProvider) Function(ctx *mysql.Context, name string) (mysql.Function, bool) {
    switch name {
    case "time_from":
    return &timeFromFunction{}, true
    case "time_to":
    return &timeToFunction{}, true
    default:
    return nil, false
    }
    }