github.com/dolthub/go-mysql-server@v0.18.0/sql/expression/function/aggregation/window/first_value.go (about)

     1  // Copyright 2021 Dolthub, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package window
    16  
    17  import (
    18  	"fmt"
    19  	"strings"
    20  
    21  	"github.com/dolthub/go-mysql-server/sql/transform"
    22  
    23  	"github.com/dolthub/go-mysql-server/sql"
    24  	"github.com/dolthub/go-mysql-server/sql/expression"
    25  	"github.com/dolthub/go-mysql-server/sql/expression/function/aggregation"
    26  )
    27  
    28  type FirstValue struct {
    29  	window *sql.WindowDefinition
    30  	expression.UnaryExpression
    31  	pos int
    32  	id  sql.ColumnId
    33  }
    34  
    35  var _ sql.FunctionExpression = (*FirstValue)(nil)
    36  var _ sql.WindowAggregation = (*FirstValue)(nil)
    37  var _ sql.WindowAdaptableExpression = (*FirstValue)(nil)
    38  var _ sql.CollationCoercible = (*FirstValue)(nil)
    39  
    40  func NewFirstValue(e sql.Expression) sql.Expression {
    41  	return &FirstValue{UnaryExpression: expression.UnaryExpression{Child: e}}
    42  }
    43  
    44  // Id implements sql.IdExpression
    45  func (f *FirstValue) Id() sql.ColumnId {
    46  	return f.id
    47  }
    48  
    49  // WithId implements sql.IdExpression
    50  func (f *FirstValue) WithId(id sql.ColumnId) sql.IdExpression {
    51  	ret := *f
    52  	ret.id = id
    53  	return &ret
    54  }
    55  
    56  // Description implements sql.FunctionExpression
    57  func (f *FirstValue) Description() string {
    58  	return "returns value of argument from first row of window frame."
    59  }
    60  
    61  // Window implements sql.WindowExpression
    62  func (f *FirstValue) Window() *sql.WindowDefinition {
    63  	return f.window
    64  }
    65  
    66  // IsNullable implements sql.Expression
    67  func (f *FirstValue) Resolved() bool {
    68  	return windowResolved(f.window)
    69  }
    70  
    71  func (f *FirstValue) String() string {
    72  	sb := strings.Builder{}
    73  	sb.WriteString(fmt.Sprintf("first_value(%s)", f.Child.String()))
    74  	if f.window != nil {
    75  		sb.WriteString(" ")
    76  		sb.WriteString(f.window.String())
    77  	}
    78  	return sb.String()
    79  }
    80  
    81  func (f *FirstValue) DebugString() string {
    82  	sb := strings.Builder{}
    83  	sb.WriteString(fmt.Sprintf("first_value(%s)", f.Child.String()))
    84  	if f.window != nil {
    85  		sb.WriteString(" ")
    86  		sb.WriteString(sql.DebugString(f.window))
    87  	}
    88  	return sb.String()
    89  }
    90  
    91  // FunctionName implements sql.FunctionExpression
    92  func (f *FirstValue) FunctionName() string {
    93  	return "FIRST_VALUE"
    94  }
    95  
    96  // Type implements sql.Expression
    97  func (f *FirstValue) Type() sql.Type {
    98  	return f.Child.Type()
    99  }
   100  
   101  // CollationCoercibility implements the interface sql.CollationCoercible.
   102  func (f *FirstValue) CollationCoercibility(ctx *sql.Context) (collation sql.CollationID, coercibility byte) {
   103  	return sql.GetCoercibility(ctx, f.Child)
   104  }
   105  
   106  // IsNullable implements sql.Expression
   107  func (f *FirstValue) IsNullable() bool {
   108  	return false
   109  }
   110  
   111  // Eval implements sql.Expression
   112  func (f *FirstValue) Eval(ctx *sql.Context, row sql.Row) (interface{}, error) {
   113  	return nil, sql.ErrWindowUnsupported.New(f.FunctionName())
   114  }
   115  
   116  // Children implements sql.Expression
   117  func (f *FirstValue) Children() []sql.Expression {
   118  	if f == nil {
   119  		return nil
   120  	}
   121  	return append(f.window.ToExpressions(), f.Child)
   122  }
   123  
   124  // WithChildren implements sql.Expression
   125  func (f *FirstValue) WithChildren(children ...sql.Expression) (sql.Expression, error) {
   126  	if len(children) < 2 {
   127  		return nil, sql.ErrInvalidChildrenNumber.New(f, len(children), 2)
   128  	}
   129  
   130  	nf := *f
   131  	window, err := f.window.FromExpressions(children[:len(children)-1])
   132  	if err != nil {
   133  		return nil, err
   134  	}
   135  
   136  	nf.Child = children[len(children)-1]
   137  	nf.window = window
   138  
   139  	return &nf, nil
   140  }
   141  
   142  // WithWindow implements sql.WindowAggregation
   143  func (f *FirstValue) WithWindow(window *sql.WindowDefinition) sql.WindowAdaptableExpression {
   144  	nr := *f
   145  	nr.window = window
   146  	return &nr
   147  }
   148  
   149  func (f *FirstValue) NewWindowFunction() (sql.WindowFunction, error) {
   150  	c, err := transform.Clone(f.Child)
   151  	if err != nil {
   152  		return nil, err
   153  	}
   154  	return aggregation.NewFirstAgg(c).WithWindow(f.window)
   155  }