Some checks failed
kotlin / test (push) Has been skipped
python / test (push) Has been skipped
typescript / test (push) Has been skipped
go / build darwin/amd64 (push) Has been cancelled
go / build linux/amd64 (push) Has been cancelled
go / build windows/amd64 (push) Has been cancelled
go / build darwin/arm64 (push) Has been cancelled
go / build linux/arm64 (push) Has been cancelled
go / build windows/arm64 (push) Has been cancelled
go / test (push) Has been cancelled
go / vuln_check (push) Has been cancelled
145 lines
4.1 KiB
Go
145 lines
4.1 KiB
Go
package sqlite
|
|
|
|
import (
|
|
"strings"
|
|
|
|
meyer "github.com/sqlc-dev/meyer/ast"
|
|
|
|
"github.com/sqlc-dev/sqlc/internal/sql/ast"
|
|
)
|
|
|
|
// identifier folds a name the way SQLite resolves one: an unquoted name is
|
|
// case-insensitive and normalizes to lower case, while a quoted name keeps
|
|
// the spelling that appeared between the quotes.
|
|
func identifier(n *meyer.Ident) string {
|
|
if n == nil {
|
|
return ""
|
|
}
|
|
if n.Quote == meyer.QuoteNone {
|
|
return strings.ToLower(n.Name)
|
|
}
|
|
return n.Name
|
|
}
|
|
|
|
// NewIdentifier returns the folded name of id as an ast.String, the shape
|
|
// sqlc uses for the parts of a ColumnRef or a function name.
|
|
func NewIdentifier(id *meyer.Ident) *ast.String {
|
|
return &ast.String{Str: identifier(id)}
|
|
}
|
|
|
|
func parseTableName(n *meyer.QualifiedName) *ast.TableName {
|
|
if n == nil {
|
|
return &ast.TableName{}
|
|
}
|
|
return &ast.TableName{
|
|
Schema: identifier(n.Schema),
|
|
Name: identifier(n.Name),
|
|
}
|
|
}
|
|
|
|
// parseRangeVar builds the relation reference sqlc expects for a table named
|
|
// in a FROM, INSERT, UPDATE or DELETE clause.
|
|
func parseRangeVar(n *meyer.QualifiedName, alias *meyer.Ident) *ast.RangeVar {
|
|
rv := &ast.RangeVar{}
|
|
if n == nil {
|
|
return rv
|
|
}
|
|
rv.Location = n.Pos()
|
|
name := identifier(n.Name)
|
|
rv.Relname = &name
|
|
if n.Schema != nil {
|
|
schema := identifier(n.Schema)
|
|
rv.Schemaname = &schema
|
|
}
|
|
if alias != nil {
|
|
aliasName := identifier(alias)
|
|
rv.Alias = &ast.Alias{Aliasname: &aliasName}
|
|
}
|
|
return rv
|
|
}
|
|
|
|
// typeName renders a type the way sqlc's type resolution expects to see it:
|
|
// the tokens joined without separators, matching what the ANTLR parser's
|
|
// GetText produced. "UNSIGNED BIG INT" becomes "UNSIGNEDBIGINT" and
|
|
// "DECIMAL(10, 5)" becomes "DECIMAL(10,5)".
|
|
func typeName(n *meyer.TypeName) string {
|
|
if n == nil {
|
|
return ""
|
|
}
|
|
var sb strings.Builder
|
|
sb.WriteString(strings.ReplaceAll(n.Name, " ", ""))
|
|
if len(n.Args) > 0 {
|
|
sb.WriteString("(")
|
|
sb.WriteString(strings.Join(n.Args, ","))
|
|
sb.WriteString(")")
|
|
}
|
|
return sb.String()
|
|
}
|
|
|
|
// typeSpelling returns the type as the author wrote it — identifier tokens
|
|
// space-joined, arguments as written — for the formatter to print back.
|
|
// typeName folds the spaces out for catalog matching.
|
|
func typeSpelling(n *meyer.TypeName) string {
|
|
if n == nil {
|
|
return ""
|
|
}
|
|
var sb strings.Builder
|
|
sb.WriteString(n.Name)
|
|
if len(n.Args) > 0 {
|
|
sb.WriteString("(")
|
|
sb.WriteString(strings.Join(n.Args, ","))
|
|
sb.WriteString(")")
|
|
}
|
|
return sb.String()
|
|
}
|
|
|
|
// representableColumn reports whether a column definition round-trips
|
|
// through the fields ast.ColumnDef models: a plain NOT NULL, a plain
|
|
// PRIMARY KEY, or nothing. Anything else — a named constraint, a conflict
|
|
// clause, ASC/DESC or AUTOINCREMENT, DEFAULT, UNIQUE, CHECK, COLLATE,
|
|
// REFERENCES, GENERATED — is parsed away, so a statement printing such a
|
|
// column would lose it. NOT NULL next to PRIMARY KEY is also beyond the
|
|
// node: SQLite's PRIMARY KEY does not imply NOT NULL, and the printed form
|
|
// carries only one of the pair.
|
|
func representableColumn(def *meyer.ColumnDef) bool {
|
|
var notNull, primary bool
|
|
for _, con := range def.Constraints {
|
|
switch {
|
|
case con.Name != nil:
|
|
return false
|
|
case con.Kind == meyer.ColumnNotNull && con.OnConflict == meyer.ConflictDefault:
|
|
notNull = true
|
|
case con.Kind == meyer.ColumnPrimaryKey && con.OnConflict == meyer.ConflictDefault &&
|
|
con.Order == meyer.SortDefault && !con.AutoIncrement:
|
|
primary = true
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
return !(notNull && primary)
|
|
}
|
|
|
|
// hasPrimaryKeyConstraint reports whether a column definition carries a
|
|
// PRIMARY KEY constraint.
|
|
func hasPrimaryKeyConstraint(constraints []*meyer.ColumnConstraint) bool {
|
|
for _, constraint := range constraints {
|
|
if constraint.Kind == meyer.ColumnPrimaryKey {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// hasNotNullConstraint reports whether a column definition guarantees a
|
|
// value. A PRIMARY KEY implies NOT NULL for the purposes of code
|
|
// generation, matching the behavior of the previous parser.
|
|
func hasNotNullConstraint(constraints []*meyer.ColumnConstraint) bool {
|
|
for _, constraint := range constraints {
|
|
switch constraint.Kind {
|
|
case meyer.ColumnNotNull, meyer.ColumnPrimaryKey:
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|