sq/libsq/ast/selector.go
Neil O'Toole d3e6f89829
SLQ support for column aliases (#150)
* alias: more early work

* alias: test cases working for sqlite

* alias: SQL builder tests

* alias: func (col expr) aliases now working for SQLite

* linting

* CHANGELOG update

* Docs update

* Docs update

* Rename buildAst() -> buildAST()

* CHANGELOG typo
2023-03-18 22:58:00 -06:00

142 lines
3.0 KiB
Go

package ast
import (
"fmt"
"github.com/antlr/antlr4/runtime/Go/antlr/v4"
"github.com/neilotoole/sq/libsq/ast/internal/slq"
)
const (
msgNodeNoAddChild = "%T cannot add children: failed to add %T"
msgNodeNoAddChildren = "%T cannot add children: failed to add %d children"
)
var _ Node = (*Selector)(nil)
// Selector is a selector such as ".my_table" or ".my_col". The
// generic selector will typically be replaced with a more specific
// selector node such as TblSelector or ColSelector.
type Selector struct {
baseNode
// alias is the (optional) alias part. For example, given ".first_name:given_name",
// the alias value is "given_name". May be empy.
alias string
}
func (s *Selector) String() string {
return nodeString(s)
}
func (s *Selector) SelValue() string {
return s.ctx.GetText()[1:]
}
var _ Node = (*TblSelector)(nil)
// TblSelector is a selector for a table, such as ".my_table"
// or "@my_src.my_table".
type TblSelector struct {
Selector
DSName string
TblName string
}
func newTblSelector(seg *Segment, tblName string, ctx antlr.ParseTree) *TblSelector {
tbl := &TblSelector{}
tbl.parent = seg
tbl.ctx = ctx
tbl.TblName = tblName
return tbl
}
// Selectable implements the Selectable marker interface.
func (s *TblSelector) Selectable() {
// no-op
}
func (s *TblSelector) SelValue() string {
return s.TblName
}
func (s *TblSelector) String() string {
text := nodeString(s)
text += fmt.Sprintf(" | table: %q | datasource: %q", s.SelValue(), s.DSName)
return text
}
var (
_ Node = (*ColSelector)(nil)
_ ColExpr = (*ColSelector)(nil)
)
// ColSelector models a column selector such as ".user_id".
type ColSelector struct {
Selector
alias string
}
func newColSelector(parent Node, ctx antlr.ParseTree, alias string) *ColSelector {
col := &ColSelector{}
col.parent = parent
col.ctx = ctx
col.alias = alias
return col
}
// ColExpr returns the column name.
func (s *ColSelector) ColExpr() (string, error) {
// Drop the leading dot, e.g. ".user" -> "user"
return s.Text()[1:], nil
}
// IsColName always returns true.
func (s *ColSelector) IsColName() bool {
return true
}
// Alias returns the column alias, which may be empty.
// For example, given the selector ".first_name:given_name", the alias is "given_name".
func (s *ColSelector) Alias() string {
return s.alias
}
// String returns a log/debug-friendly representation.
func (s *ColSelector) String() string {
str := nodeString(s)
if s.alias != "" {
str += ":" + s.alias
}
return str
}
var _ Node = (*Cmpr)(nil)
// Cmpr models a comparison, such as ".age == 42".
type Cmpr struct {
baseNode
}
func (c *Cmpr) String() string {
return nodeString(c)
}
func newCmpr(parent Node, ctx slq.ICmprContext) *Cmpr {
leaf, _ := ctx.GetChild(0).(*antlr.TerminalNodeImpl)
cmpr := &Cmpr{}
cmpr.ctx = leaf
cmpr.parent = parent
return cmpr
}
// Datasource models a source such as "@sakila_sl3".
type Datasource struct {
baseNode
}
func (d *Datasource) String() string {
return nodeString(d)
}